Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F112150844
PhabricatorProjectTransactionEditor.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Thu, May 8, 06:00
Size
14 KB
Mime Type
text/x-php
Expires
Sat, May 10, 06:00 (1 d, 23 h)
Engine
blob
Format
Raw Data
Handle
26016354
Attached To
rPH Phabricator
PhabricatorProjectTransactionEditor.php
View Options
<?php
final
class
PhabricatorProjectTransactionEditor
extends
PhabricatorApplicationTransactionEditor
{
public
function
getTransactionTypes
()
{
$types
=
parent
::
getTransactionTypes
();
$types
[]
=
PhabricatorTransactions
::
TYPE_EDGE
;
$types
[]
=
PhabricatorTransactions
::
TYPE_VIEW_POLICY
;
$types
[]
=
PhabricatorTransactions
::
TYPE_EDIT_POLICY
;
$types
[]
=
PhabricatorTransactions
::
TYPE_JOIN_POLICY
;
$types
[]
=
PhabricatorProjectTransaction
::
TYPE_NAME
;
$types
[]
=
PhabricatorProjectTransaction
::
TYPE_SLUGS
;
$types
[]
=
PhabricatorProjectTransaction
::
TYPE_STATUS
;
$types
[]
=
PhabricatorProjectTransaction
::
TYPE_IMAGE
;
$types
[]
=
PhabricatorProjectTransaction
::
TYPE_ICON
;
return
$types
;
}
protected
function
getCustomTransactionOldValue
(
PhabricatorLiskDAO
$object
,
PhabricatorApplicationTransaction
$xaction
)
{
switch
(
$xaction
->
getTransactionType
())
{
case
PhabricatorProjectTransaction
::
TYPE_NAME
:
return
$object
->
getName
();
case
PhabricatorProjectTransaction
::
TYPE_SLUGS
:
$slugs
=
$object
->
getSlugs
();
$slugs
=
mpull
(
$slugs
,
'getSlug'
,
'getSlug'
);
unset
(
$slugs
[
$object
->
getPrimarySlug
()]);
return
$slugs
;
case
PhabricatorProjectTransaction
::
TYPE_STATUS
:
return
$object
->
getStatus
();
case
PhabricatorProjectTransaction
::
TYPE_IMAGE
:
return
$object
->
getProfileImagePHID
();
case
PhabricatorProjectTransaction
::
TYPE_ICON
:
return
$object
->
getIcon
();
}
return
parent
::
getCustomTransactionOldValue
(
$object
,
$xaction
);
}
protected
function
getCustomTransactionNewValue
(
PhabricatorLiskDAO
$object
,
PhabricatorApplicationTransaction
$xaction
)
{
switch
(
$xaction
->
getTransactionType
())
{
case
PhabricatorProjectTransaction
::
TYPE_NAME
:
case
PhabricatorProjectTransaction
::
TYPE_SLUGS
:
case
PhabricatorProjectTransaction
::
TYPE_STATUS
:
case
PhabricatorProjectTransaction
::
TYPE_IMAGE
:
case
PhabricatorProjectTransaction
::
TYPE_ICON
:
return
$xaction
->
getNewValue
();
}
return
parent
::
getCustomTransactionNewValue
(
$object
,
$xaction
);
}
protected
function
applyCustomInternalTransaction
(
PhabricatorLiskDAO
$object
,
PhabricatorApplicationTransaction
$xaction
)
{
switch
(
$xaction
->
getTransactionType
())
{
case
PhabricatorProjectTransaction
::
TYPE_NAME
:
$object
->
setName
(
$xaction
->
getNewValue
());
$object
->
setPhrictionSlug
(
$xaction
->
getNewValue
());
return
;
case
PhabricatorProjectTransaction
::
TYPE_SLUGS
:
return
;
case
PhabricatorProjectTransaction
::
TYPE_STATUS
:
$object
->
setStatus
(
$xaction
->
getNewValue
());
return
;
case
PhabricatorProjectTransaction
::
TYPE_IMAGE
:
$object
->
setProfileImagePHID
(
$xaction
->
getNewValue
());
return
;
case
PhabricatorProjectTransaction
::
TYPE_ICON
:
$object
->
setIcon
(
$xaction
->
getNewValue
());
return
;
case
PhabricatorTransactions
::
TYPE_EDGE
:
return
;
case
PhabricatorTransactions
::
TYPE_VIEW_POLICY
:
$object
->
setViewPolicy
(
$xaction
->
getNewValue
());
return
;
case
PhabricatorTransactions
::
TYPE_EDIT_POLICY
:
$object
->
setEditPolicy
(
$xaction
->
getNewValue
());
return
;
case
PhabricatorTransactions
::
TYPE_JOIN_POLICY
:
$object
->
setJoinPolicy
(
$xaction
->
getNewValue
());
return
;
}
return
parent
::
applyCustomInternalTransaction
(
$object
,
$xaction
);
}
protected
function
applyCustomExternalTransaction
(
PhabricatorLiskDAO
$object
,
PhabricatorApplicationTransaction
$xaction
)
{
switch
(
$xaction
->
getTransactionType
())
{
case
PhabricatorProjectTransaction
::
TYPE_NAME
:
$new_slug
=
id
(
new
PhabricatorProjectSlug
())
->
setSlug
(
$object
->
getPrimarySlug
())
->
setProjectPHID
(
$object
->
getPHID
())
->
save
();
if
(
$xaction
->
getOldValue
()
!==
null
)
{
$clone_object
=
clone
$object
;
$clone_object
->
setPhrictionSlug
(
$xaction
->
getOldValue
());
$old_slug
=
$clone_object
->
getPrimarySlug
();
$old_slug
=
id
(
new
PhabricatorProjectSlug
())
->
loadOneWhere
(
'slug = %s'
,
$old_slug
);
if
(
$old_slug
)
{
$old_slug
->
delete
();
}
}
// TODO -- delete all of the below once we sever automagical project
// to phriction stuff
if
(
$xaction
->
getOldValue
()
===
null
)
{
// Project was just created, we don't need to move anything.
return
;
}
$clone_object
=
clone
$object
;
$clone_object
->
setPhrictionSlug
(
$xaction
->
getOldValue
());
$old_slug
=
$clone_object
->
getFullPhrictionSlug
();
$old_document
=
id
(
new
PhrictionDocument
())
->
loadOneWhere
(
'slug = %s'
,
$old_slug
);
if
(
$old_document
&&
$old_document
->
getStatus
()
==
PhrictionDocumentStatus
::
STATUS_EXISTS
)
{
$content
=
id
(
new
PhrictionContent
())
->
load
(
$old_document
->
getContentID
());
$from_editor
=
id
(
PhrictionDocumentEditor
::
newForSlug
(
$old_slug
))
->
setActor
(
$this
->
getActor
())
->
setTitle
(
$content
->
getTitle
())
->
setContent
(
$content
->
getContent
())
->
setDescription
(
$content
->
getDescription
());
$target_editor
=
id
(
PhrictionDocumentEditor
::
newForSlug
(
$object
->
getFullPhrictionSlug
()))
->
setActor
(
$this
->
getActor
())
->
setTitle
(
$content
->
getTitle
())
->
setContent
(
$content
->
getContent
())
->
setDescription
(
$content
->
getDescription
())
->
moveHere
(
$old_document
->
getID
(),
$old_document
->
getPHID
());
$target_document
=
$target_editor
->
getDocument
();
$from_editor
->
moveAway
(
$target_document
->
getID
());
}
return
;
case
PhabricatorProjectTransaction
::
TYPE_SLUGS
:
$old
=
$xaction
->
getOldValue
();
$new
=
$xaction
->
getNewValue
();
$add
=
array_diff
(
$new
,
$old
);
$rem
=
array_diff
(
$old
,
$new
);
if
(
$add
)
{
$add_slug_template
=
id
(
new
PhabricatorProjectSlug
())
->
setProjectPHID
(
$object
->
getPHID
());
foreach
(
$add
as
$add_slug_str
)
{
$add_slug
=
id
(
clone
$add_slug_template
)
->
setSlug
(
$add_slug_str
)
->
save
();
}
}
if
(
$rem
)
{
$rem_slugs
=
id
(
new
PhabricatorProjectSlug
())
->
loadAllWhere
(
'slug IN (%Ls)'
,
$rem
);
foreach
(
$rem_slugs
as
$rem_slug
)
{
$rem_slug
->
delete
();
}
}
return
;
case
PhabricatorTransactions
::
TYPE_VIEW_POLICY
:
case
PhabricatorTransactions
::
TYPE_EDIT_POLICY
:
case
PhabricatorTransactions
::
TYPE_JOIN_POLICY
:
case
PhabricatorProjectTransaction
::
TYPE_STATUS
:
case
PhabricatorProjectTransaction
::
TYPE_IMAGE
:
case
PhabricatorProjectTransaction
::
TYPE_ICON
:
return
;
case
PhabricatorTransactions
::
TYPE_EDGE
:
$edge_type
=
$xaction
->
getMetadataValue
(
'edge:type'
);
switch
(
$edge_type
)
{
case
PhabricatorEdgeConfig
::
TYPE_PROJ_MEMBER
:
case
PhabricatorEdgeConfig
::
TYPE_OBJECT_HAS_WATCHER
:
$old
=
$xaction
->
getOldValue
();
$new
=
$xaction
->
getNewValue
();
// When adding members or watchers, we add subscriptions.
$add
=
array_keys
(
array_diff_key
(
$new
,
$old
));
// When removing members, we remove their subscription too.
// When unwatching, we leave subscriptions, since it's fine to be
// subscribed to a project but not be a member of it.
if
(
$edge_type
==
PhabricatorEdgeConfig
::
TYPE_PROJ_MEMBER
)
{
$rem
=
array_keys
(
array_diff_key
(
$old
,
$new
));
}
else
{
$rem
=
array
();
}
// NOTE: The subscribe is "explicit" because there's no implicit
// unsubscribe, so Join -> Leave -> Join doesn't resubscribe you
// if we use an implicit subscribe, even though you never willfully
// unsubscribed. Not sure if adding implicit unsubscribe (which
// would not write the unsubscribe row) is justified to deal with
// this, which is a fairly weird edge case and pretty arguable both
// ways.
// Subscriptions caused by watches should also clearly be explicit,
// and that case is unambiguous.
id
(
new
PhabricatorSubscriptionsEditor
())
->
setActor
(
$this
->
requireActor
())
->
setObject
(
$object
)
->
subscribeExplicit
(
$add
)
->
unsubscribe
(
$rem
)
->
save
();
if
(
$rem
)
{
// When removing members, also remove any watches on the project.
$edge_editor
=
id
(
new
PhabricatorEdgeEditor
())
->
setSuppressEvents
(
true
);
foreach
(
$rem
as
$rem_phid
)
{
$edge_editor
->
removeEdge
(
$object
->
getPHID
(),
PhabricatorEdgeConfig
::
TYPE_OBJECT_HAS_WATCHER
,
$rem_phid
);
}
$edge_editor
->
save
();
}
break
;
}
return
;
}
return
parent
::
applyCustomExternalTransaction
(
$object
,
$xaction
);
}
protected
function
validateTransaction
(
PhabricatorLiskDAO
$object
,
$type
,
array
$xactions
)
{
$errors
=
parent
::
validateTransaction
(
$object
,
$type
,
$xactions
);
switch
(
$type
)
{
case
PhabricatorProjectTransaction
::
TYPE_NAME
:
$missing
=
$this
->
validateIsEmptyTextField
(
$object
->
getName
(),
$xactions
);
if
(
$missing
)
{
$error
=
new
PhabricatorApplicationTransactionValidationError
(
$type
,
pht
(
'Required'
),
pht
(
'Project name is required.'
),
nonempty
(
last
(
$xactions
),
null
));
$error
->
setIsMissingFieldError
(
true
);
$errors
[]
=
$error
;
}
if
(!
$xactions
)
{
break
;
}
$name
=
last
(
$xactions
)->
getNewValue
();
$name_used_already
=
id
(
new
PhabricatorProjectQuery
())
->
setViewer
(
$this
->
getActor
())
->
withNames
(
array
(
$name
))
->
executeOne
();
if
(
$name_used_already
&&
(
$name_used_already
->
getPHID
()
!=
$object
->
getPHID
()))
{
$error
=
new
PhabricatorApplicationTransactionValidationError
(
$type
,
pht
(
'Duplicate'
),
pht
(
'Project name is already used.'
),
nonempty
(
last
(
$xactions
),
null
));
$errors
[]
=
$error
;
}
$slug_builder
=
clone
$object
;
$slug_builder
->
setPhrictionSlug
(
$name
);
$slug
=
$slug_builder
->
getPrimarySlug
();
$slug_used_already
=
id
(
new
PhabricatorProjectSlug
())
->
loadOneWhere
(
'slug = %s'
,
$slug
);
if
(
$slug_used_already
&&
$slug_used_already
->
getProjectPHID
()
!=
$object
->
getPHID
())
{
$error
=
new
PhabricatorApplicationTransactionValidationError
(
$type
,
pht
(
'Duplicate'
),
pht
(
'Project name can not be used due to hashtag collision.'
),
nonempty
(
last
(
$xactions
),
null
));
$errors
[]
=
$error
;
}
break
;
case
PhabricatorProjectTransaction
::
TYPE_SLUGS
:
if
(!
$xactions
)
{
break
;
}
$slug_xaction
=
last
(
$xactions
);
$new
=
$slug_xaction
->
getNewValue
();
$slugs_used_already
=
id
(
new
PhabricatorProjectSlug
())
->
loadAllWhere
(
'slug IN (%Ls)'
,
$new
);
$slugs_used_already
=
mgroup
(
$slugs_used_already
,
'getProjectPHID'
);
foreach
(
$slugs_used_already
as
$project_phid
=>
$used_slugs
)
{
$used_slug_strs
=
mpull
(
$used_slugs
,
'getSlug'
);
if
(
$project_phid
==
$object
->
getPHID
())
{
if
(
in_array
(
$object
->
getPrimarySlug
(),
$used_slug_strs
))
{
$error
=
new
PhabricatorApplicationTransactionValidationError
(
$type
,
pht
(
'Invalid'
),
pht
(
'Project hashtag %s is already the primary hashtag.'
,
$object
->
getPrimarySlug
()),
$slug_xaction
);
$errors
[]
=
$error
;
}
continue
;
}
$error
=
new
PhabricatorApplicationTransactionValidationError
(
$type
,
pht
(
'Invalid'
),
pht
(
'%d project hashtag(s) are already used: %s'
,
count
(
$used_slug_strs
),
implode
(
', '
,
$used_slug_strs
)),
$slug_xaction
);
$errors
[]
=
$error
;
}
break
;
}
return
$errors
;
}
protected
function
requireCapabilities
(
PhabricatorLiskDAO
$object
,
PhabricatorApplicationTransaction
$xaction
)
{
switch
(
$xaction
->
getTransactionType
())
{
case
PhabricatorProjectTransaction
::
TYPE_NAME
:
case
PhabricatorProjectTransaction
::
TYPE_STATUS
:
case
PhabricatorProjectTransaction
::
TYPE_IMAGE
:
case
PhabricatorProjectTransaction
::
TYPE_ICON
:
PhabricatorPolicyFilter
::
requireCapability
(
$this
->
requireActor
(),
$object
,
PhabricatorPolicyCapability
::
CAN_EDIT
);
return
;
case
PhabricatorTransactions
::
TYPE_EDGE
:
switch
(
$xaction
->
getMetadataValue
(
'edge:type'
))
{
case
PhabricatorEdgeConfig
::
TYPE_PROJ_MEMBER
:
$old
=
$xaction
->
getOldValue
();
$new
=
$xaction
->
getNewValue
();
$add
=
array_keys
(
array_diff_key
(
$new
,
$old
));
$rem
=
array_keys
(
array_diff_key
(
$old
,
$new
));
$actor_phid
=
$this
->
requireActor
()->
getPHID
();
$is_join
=
((
$add
===
array
(
$actor_phid
))
&&
!
$rem
);
$is_leave
=
((
$rem
===
array
(
$actor_phid
))
&&
!
$add
);
if
(
$is_join
)
{
// You need CAN_JOIN to join a project.
PhabricatorPolicyFilter
::
requireCapability
(
$this
->
requireActor
(),
$object
,
PhabricatorPolicyCapability
::
CAN_JOIN
);
}
else
if
(
$is_leave
)
{
// You don't need any capabilities to leave a project.
}
else
{
// You need CAN_EDIT to change members other than yourself.
PhabricatorPolicyFilter
::
requireCapability
(
$this
->
requireActor
(),
$object
,
PhabricatorPolicyCapability
::
CAN_EDIT
);
}
return
;
}
break
;
}
return
parent
::
requireCapabilities
(
$object
,
$xaction
);
}
protected
function
supportsSearch
()
{
return
true
;
}
protected
function
extractFilePHIDsFromCustomTransaction
(
PhabricatorLiskDAO
$object
,
PhabricatorApplicationTransaction
$xaction
)
{
switch
(
$xaction
->
getTransactionType
())
{
case
PhabricatorProjectTransaction
::
TYPE_IMAGE
:
$new
=
$xaction
->
getNewValue
();
if
(
$new
)
{
return
array
(
$new
);
}
break
;
}
return
parent
::
extractFilePHIDsFromCustomTransaction
(
$object
,
$xaction
);
}
}
Event Timeline
Log In to Comment