mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 16:52:41 +01:00
Merge branch 'master' of github.com:facebook/phabricator
This commit is contained in:
commit
a22827865f
181 changed files with 6816 additions and 695 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -11,3 +11,6 @@
|
|||
|
||||
# NetBeans project files
|
||||
/nbproject/
|
||||
|
||||
# Arcanist scratch directory
|
||||
/.arc
|
||||
|
|
|
@ -329,7 +329,7 @@ return array(
|
|||
'account.minimum-password-length' => 8,
|
||||
|
||||
|
||||
// -- Facebook ------------------------------------------------------------ //
|
||||
// -- Facebook OAuth -------------------------------------------------------- //
|
||||
|
||||
// Can users use Facebook credentials to login to Phabricator?
|
||||
'facebook.auth-enabled' => false,
|
||||
|
@ -348,7 +348,7 @@ return array(
|
|||
'facebook.application-secret' => null,
|
||||
|
||||
|
||||
// -- GitHub ---------------------------------------------------------------- //
|
||||
// -- GitHub OAuth ---------------------------------------------------------- //
|
||||
|
||||
// Can users use GitHub credentials to login to Phabricator?
|
||||
'github.auth-enabled' => false,
|
||||
|
@ -367,7 +367,7 @@ return array(
|
|||
'github.application-secret' => null,
|
||||
|
||||
|
||||
// -- Google ---------------------------------------------------------------- //
|
||||
// -- Google OAuth ---------------------------------------------------------- //
|
||||
|
||||
// Can users use Google credentials to login to Phabricator?
|
||||
'google.auth-enabled' => false,
|
||||
|
@ -385,6 +385,30 @@ return array(
|
|||
// The Google "Client Secret" to use for Google API access.
|
||||
'google.application-secret' => null,
|
||||
|
||||
// -- Phabricator OAuth ----------------------------------------------------- //
|
||||
|
||||
// Meta-town -- Phabricator is itself an OAuth Provider
|
||||
// TODO -- T887 -- make this support multiple Phabricator instances!
|
||||
|
||||
// The URI of the Phabricator instance to use as an OAuth server.
|
||||
'phabricator.oauth-uri' => null,
|
||||
|
||||
// Can users use Phabricator credentials to login to Phabricator?
|
||||
'phabricator.auth-enabled' => false,
|
||||
|
||||
// Can users use Phabricator credentials to create new Phabricator accounts?
|
||||
'phabricator.registration-enabled' => true,
|
||||
|
||||
// Are Phabricator accounts permanently linked to Phabricator accounts, or can
|
||||
// the user unlink them?
|
||||
'phabricator.auth-permanent' => false,
|
||||
|
||||
// The Phabricator "Client ID" to use for Phabricator API access.
|
||||
'phabricator.application-id' => null,
|
||||
|
||||
// The Phabricator "Client Secret" to use for Phabricator API access.
|
||||
'phabricator.application-secret' => null,
|
||||
|
||||
// -- Recaptcha ------------------------------------------------------------- //
|
||||
|
||||
// Is Recaptcha enabled? If disabled, captchas will not appear. You should
|
||||
|
@ -623,6 +647,10 @@ return array(
|
|||
// Adding Custom Fields" in the documentation for more information.
|
||||
'maniphest.custom-task-extensions-class' => 'ManiphestDefaultTaskExtensions',
|
||||
|
||||
// -- Phriction ------------------------------------------------------------- //
|
||||
|
||||
'phriction.enabled' => true,
|
||||
|
||||
// -- Remarkup -------------------------------------------------------------- //
|
||||
|
||||
// If you enable this, linked YouTube videos will be embeded inline. This has
|
||||
|
|
2
externals/javelin
vendored
2
externals/javelin
vendored
|
@ -1 +1 @@
|
|||
Subproject commit f25470da2c98cd37fbac435a56128b1d465f7667
|
||||
Subproject commit 14f4218c5b7d50bb0f4144d937e482cdb98f6cdb
|
10
externals/raphael/g.raphael.js
vendored
Normal file
10
externals/raphael/g.raphael.js
vendored
Normal file
File diff suppressed because one or more lines are too long
10
externals/raphael/g.raphael.line.js
vendored
Normal file
10
externals/raphael/g.raphael.line.js
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* @provides raphael-g-line
|
||||
*/
|
||||
/*!
|
||||
* g.Raphael 0.5 - Charting library, based on Raphaël
|
||||
*
|
||||
* Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
|
||||
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
|
||||
*/
|
||||
(function(){function a(g,n){var f=g.length/n,h=0,e=f,m=0,i=[];while(h<g.length){e--;if(e<0){m+=g[h]*(1+e);i.push(m/f);m=g[h++]*-e;e+=f}else{m+=g[h++]}}return i}function d(f,e,p,n,k,j){var h=(p-f)/2,g=(k-p)/2,q=Math.atan((p-f)/Math.abs(n-e)),o=Math.atan((k-p)/Math.abs(n-j));q=e<n?Math.PI-q:q;o=j<n?Math.PI-o:o;var i=Math.PI/2-((q+o)%(Math.PI*2))/2,s=h*Math.sin(i+q),m=h*Math.cos(i+q),r=g*Math.sin(i+o),l=g*Math.cos(i+o);return{x1:p-s,y1:n+m,x2:p+r,y2:n+l}}function b(f,P,O,e,h,A,z,J){var s=this;J=J||{};if(!f.raphael.is(A[0],"array")){A=[A]}if(!f.raphael.is(z[0],"array")){z=[z]}var q=J.gutter||10,B=Math.max(A[0].length,z[0].length),t=J.symbol||"",S=J.colors||s.colors,v=null,p=null,ad=f.set(),T=[];for(var ac=0,L=z.length;ac<L;ac++){B=Math.max(B,z[ac].length)}var ae=f.set();for(ac=0,L=z.length;ac<L;ac++){if(J.shade){ae.push(f.path().attr({stroke:"none",fill:S[ac],opacity:J.nostroke?1:0.3}))}if(z[ac].length>e-2*q){z[ac]=a(z[ac],e-2*q);B=e-2*q}if(A[ac]&&A[ac].length>e-2*q){A[ac]=a(A[ac],e-2*q)}}var W=Array.prototype.concat.apply([],A),U=Array.prototype.concat.apply([],z),u=s.snapEnds(Math.min.apply(Math,W),Math.max.apply(Math,W),A[0].length-1),E=u.from,o=u.to,N=s.snapEnds(Math.min.apply(Math,U),Math.max.apply(Math,U),z[0].length-1),C=N.from,n=N.to,Z=(e-q*2)/((o-E)||1),V=(h-q*2)/((n-C)||1);var G=f.set();if(J.axis){var m=(J.axis+"").split(/[,\s]+/);+m[0]&&G.push(s.axis(P+q,O+q,e-2*q,E,o,J.axisxstep||Math.floor((e-2*q)/20),2,f));+m[1]&&G.push(s.axis(P+e-q,O+h-q,h-2*q,C,n,J.axisystep||Math.floor((h-2*q)/20),3,f));+m[2]&&G.push(s.axis(P+q,O+h-q,e-2*q,E,o,J.axisxstep||Math.floor((e-2*q)/20),0,f));+m[3]&&G.push(s.axis(P+q,O+h-q,h-2*q,C,n,J.axisystep||Math.floor((h-2*q)/20),1,f))}var M=f.set(),aa=f.set(),r;for(ac=0,L=z.length;ac<L;ac++){if(!J.nostroke){M.push(r=f.path().attr({stroke:S[ac],"stroke-width":J.width||2,"stroke-linejoin":"round","stroke-linecap":"round","stroke-dasharray":J.dash||""}))}var g=Raphael.is(t,"array")?t[ac]:t,H=f.set();T=[];for(var ab=0,w=z[ac].length;ab<w;ab++){var l=P+q+((A[ac]||A[0])[ab]-E)*Z,k=O+h-q-(z[ac][ab]-C)*V;(Raphael.is(g,"array")?g[ab]:g)&&H.push(f[Raphael.is(g,"array")?g[ab]:g](l,k,(J.width||2)*3).attr({fill:S[ac],stroke:"none"}));if(J.smooth){if(ab&&ab!=w-1){var R=P+q+((A[ac]||A[0])[ab-1]-E)*Z,F=O+h-q-(z[ac][ab-1]-C)*V,Q=P+q+((A[ac]||A[0])[ab+1]-E)*Z,D=O+h-q-(z[ac][ab+1]-C)*V,af=d(R,F,l,k,Q,D);T=T.concat([af.x1,af.y1,l,k,af.x2,af.y2])}if(!ab){T=["M",l,k,"C",l,k]}}else{T=T.concat([ab?"L":"M",l,k])}}if(J.smooth){T=T.concat([l,k,l,k])}aa.push(H);if(J.shade){ae[ac].attr({path:T.concat(["L",l,O+h-q,"L",P+q+((A[ac]||A[0])[0]-E)*Z,O+h-q,"z"]).join(",")})}!J.nostroke&&r.attr({path:T.join(",")})}function K(an){var ak=[];for(var al=0,ap=A.length;al<ap;al++){ak=ak.concat(A[al])}ak.sort();var aq=[],ah=[];for(al=0,ap=ak.length;al<ap;al++){ak[al]!=ak[al-1]&&aq.push(ak[al])&&ah.push(P+q+(ak[al]-E)*Z)}ak=aq;ap=ak.length;var ag=an||f.set();for(al=0;al<ap;al++){var Y=ah[al]-(ah[al]-(ah[al-1]||P))/2,ao=((ah[al+1]||P+e)-ah[al])/2+(ah[al]-(ah[al-1]||P))/2,x;an?(x={}):ag.push(x=f.rect(Y-1,O,Math.max(ao+1,1),h).attr({stroke:"none",fill:"#000",opacity:0}));x.values=[];x.symbols=f.set();x.y=[];x.x=ah[al];x.axis=ak[al];for(var aj=0,am=z.length;aj<am;aj++){aq=A[aj]||A[0];for(var ai=0,y=aq.length;ai<y;ai++){if(aq[ai]==ak[al]){x.values.push(z[aj][ai]);x.y.push(O+h-q-(z[aj][ai]-C)*V);x.symbols.push(ad.symbols[aj][ai])}}}an&&an.call(x)}!an&&(v=ag)}function I(al){var ah=al||f.set(),x;for(var aj=0,an=z.length;aj<an;aj++){for(var ai=0,ak=z[aj].length;ai<ak;ai++){var ag=P+q+((A[aj]||A[0])[ai]-E)*Z,am=P+q+((A[aj]||A[0])[ai?ai-1:1]-E)*Z,y=O+h-q-(z[aj][ai]-C)*V;al?(x={}):ah.push(x=f.circle(ag,y,Math.abs(am-ag)/2).attr({stroke:"none",fill:"#000",opacity:0}));x.x=ag;x.y=y;x.value=z[aj][ai];x.line=ad.lines[aj];x.shade=ad.shades[aj];x.symbol=ad.symbols[aj][ai];x.symbols=ad.symbols[aj];x.axis=(A[aj]||A[0])[ai];al&&al.call(x)}}!al&&(p=ah)}ad.push(M,ae,aa,G,v,p);ad.lines=M;ad.shades=ae;ad.symbols=aa;ad.axis=G;ad.hoverColumn=function(j,i){!v&&K();v.mouseover(j).mouseout(i);return this};ad.clickColumn=function(i){!v&&K();v.click(i);return this};ad.hrefColumn=function(Y){var ag=f.raphael.is(arguments[0],"array")?arguments[0]:arguments;if(!(arguments.length-1)&&typeof Y=="object"){for(var j in Y){for(var y=0,X=v.length;y<X;y++){if(v[y].axis==j){v[y].attr("href",Y[j])}}}}!v&&K();for(y=0,X=ag.length;y<X;y++){v[y]&&v[y].attr("href",ag[y])}return this};ad.hover=function(j,i){!p&&I();p.mouseover(j).mouseout(i);return this};ad.click=function(i){!p&&I();p.click(i);return this};ad.each=function(i){I(i);return this};ad.eachColumn=function(i){K(i);return this};return ad}var c=function(){};c.prototype=Raphael.g;b.prototype=new c;Raphael.fn.linechart=function(f,k,g,e,j,i,h){return new b(this,f,k,g,e,j,i,h)}})();
|
11
externals/raphael/raphael.js
vendored
Normal file
11
externals/raphael/raphael.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -9,6 +9,7 @@
|
|||
"PhabricatorIRCProtocolHandler",
|
||||
"PhabricatorIRCObjectNameHandler",
|
||||
"PhabricatorIRCLogHandler",
|
||||
"PhabricatorIRCWhatsNewHandler",
|
||||
"PhabricatorIRCDifferentialNotificationHandler"
|
||||
],
|
||||
|
||||
|
|
51
resources/sql/patches/107.oauthserver.sql
Normal file
51
resources/sql/patches/107.oauthserver.sql
Normal file
|
@ -0,0 +1,51 @@
|
|||
CREATE DATABASE IF NOT EXISTS `phabricator_oauth_server`;
|
||||
|
||||
CREATE TABLE `phabricator_oauth_server`.`oauth_server_oauthserverclient` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`phid` varchar(64) BINARY NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`secret` varchar(32) NOT NULL,
|
||||
`redirectURI` varchar(255) NOT NULL,
|
||||
`creatorPHID` varchar(64) BINARY NOT NULL,
|
||||
`dateCreated` int(10) unsigned NOT NULL,
|
||||
`dateModified` int(10) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `phid` (`phid`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE `phabricator_oauth_server`.`oauth_server_oauthclientauthorization` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`phid` varchar(64) BINARY NOT NULL,
|
||||
`userPHID` varchar(64) BINARY NOT NULL,
|
||||
`clientPHID` varchar(64) BINARY NOT NULL,
|
||||
`dateCreated` int(10) unsigned NOT NULL,
|
||||
`dateModified` int(10) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `phid` (`phid`),
|
||||
UNIQUE KEY `userPHID` (`userPHID`,`clientPHID`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE `phabricator_oauth_server`.`oauth_server_oauthserverauthorizationcode` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`code` varchar(32) NOT NULL,
|
||||
`clientPHID` varchar(64) BINARY NOT NULL,
|
||||
`clientSecret` varchar(32) NOT NULL,
|
||||
`userPHID` varchar(64) BINARY NOT NULL,
|
||||
`dateCreated` int(10) unsigned NOT NULL,
|
||||
`dateModified` int(10) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `code` (`code`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE `phabricator_oauth_server`.`oauth_server_oauthserveraccesstoken` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`token` varchar(32) NOT NULL,
|
||||
`userPHID` varchar(64) BINARY NOT NULL,
|
||||
`clientPHID` varchar(64) BINARY NOT NULL,
|
||||
`dateExpires` int(10) unsigned NOT NULL,
|
||||
`dateCreated` int(10) unsigned NOT NULL,
|
||||
`dateModified` int(10) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `token` (`token`)
|
||||
) ENGINE=InnoDB;
|
||||
|
6
resources/sql/patches/108.oauthscope.sql
Normal file
6
resources/sql/patches/108.oauthscope.sql
Normal file
|
@ -0,0 +1,6 @@
|
|||
ALTER TABLE `phabricator_oauth_server`.`oauth_server_oauthclientauthorization`
|
||||
ADD `scope` text NOT NULL;
|
||||
|
||||
ALTER TABLE `phabricator_oauth_server`.`oauth_server_oauthserveraccesstoken`
|
||||
DROP `dateExpires`;
|
||||
|
3
resources/sql/patches/109.oauthclientphidkey.sql
Normal file
3
resources/sql/patches/109.oauthclientphidkey.sql
Normal file
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE `phabricator_oauth_server`.`oauth_server_oauthserverclient`
|
||||
ADD KEY `creatorPHID` (`creatorPHID`)
|
||||
|
|
@ -213,7 +213,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'differential-revision-comment-css' =>
|
||||
array(
|
||||
'uri' => '/res/be9a95b4/rsrc/css/application/differential/revision-comment.css',
|
||||
'uri' => '/res/7a0002f1/rsrc/css/application/differential/revision-comment.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -258,7 +258,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'diffusion-commit-view-css' =>
|
||||
array(
|
||||
'uri' => '/res/bc39d876/rsrc/css/application/diffusion/commit-view.css',
|
||||
'uri' => '/res/d486f79a/rsrc/css/application/diffusion/commit-view.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -361,13 +361,14 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'javelin-behavior-aphront-drag-and-drop-textarea' =>
|
||||
array(
|
||||
'uri' => '/res/fa7527f9/rsrc/js/application/core/behavior-drag-and-drop-textarea.js',
|
||||
'uri' => '/res/65980508/rsrc/js/application/core/behavior-drag-and-drop-textarea.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-dom',
|
||||
2 => 'phabricator-drag-and-drop-file-upload',
|
||||
3 => 'phabricator-paste-file-upload',
|
||||
),
|
||||
'disk' => '/rsrc/js/application/core/behavior-drag-and-drop-textarea.js',
|
||||
),
|
||||
|
@ -383,6 +384,19 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/js/application/core/behavior-form.js',
|
||||
),
|
||||
'javelin-behavior-buoyant' =>
|
||||
array(
|
||||
'uri' => '/res/e7581db1/rsrc/js/application/core/behavior-buoyant.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-stratcom',
|
||||
2 => 'javelin-vector',
|
||||
3 => 'javelin-dom',
|
||||
),
|
||||
'disk' => '/rsrc/js/application/core/behavior-buoyant.js',
|
||||
),
|
||||
'javelin-behavior-countdown-timer' =>
|
||||
array(
|
||||
'uri' => '/res/5ee9cb13/rsrc/js/application/countdown/timer.js',
|
||||
|
@ -616,6 +630,36 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/js/application/herald/herald-rule-editor.js',
|
||||
),
|
||||
'javelin-behavior-maniphest-batch-editor' =>
|
||||
array(
|
||||
'uri' => '/res/d7b7f061/rsrc/js/application/maniphest/behavior-batch-editor.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-dom',
|
||||
2 => 'javelin-util',
|
||||
3 => 'phabricator-prefab',
|
||||
4 => 'multirow-row-manager',
|
||||
5 => 'javelin-tokenizer',
|
||||
6 => 'javelin-typeahead-preloaded-source',
|
||||
7 => 'javelin-typeahead',
|
||||
8 => 'javelin-json',
|
||||
),
|
||||
'disk' => '/rsrc/js/application/maniphest/behavior-batch-editor.js',
|
||||
),
|
||||
'javelin-behavior-maniphest-batch-selector' =>
|
||||
array(
|
||||
'uri' => '/res/398cf8d7/rsrc/js/application/maniphest/behavior-batch-selector.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-dom',
|
||||
2 => 'javelin-stratcom',
|
||||
),
|
||||
'disk' => '/rsrc/js/application/maniphest/behavior-batch-selector.js',
|
||||
),
|
||||
'javelin-behavior-maniphest-description-preview' =>
|
||||
array(
|
||||
'uri' => '/res/8acd6f07/rsrc/js/application/maniphest/behavior-task-preview.js',
|
||||
|
@ -858,7 +902,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'javelin-dom' =>
|
||||
array(
|
||||
'uri' => '/res/b2e8a5b6/rsrc/js/javelin/lib/DOM.js',
|
||||
'uri' => '/res/4c86aaeb/rsrc/js/javelin/lib/DOM.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -941,7 +985,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'javelin-magical-init' =>
|
||||
array(
|
||||
'uri' => '/res/0e72d59b/rsrc/js/javelin/core/init.js',
|
||||
'uri' => '/res/caa86a45/rsrc/js/javelin/core/init.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -1012,7 +1056,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'javelin-request' =>
|
||||
array(
|
||||
'uri' => '/res/b3257b7d/rsrc/js/javelin/lib/Request.js',
|
||||
'uri' => '/res/6ccc1d5a/rsrc/js/javelin/lib/Request.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -1040,7 +1084,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'javelin-stratcom' =>
|
||||
array(
|
||||
'uri' => '/res/d7a3d1e9/rsrc/js/javelin/core/Stratcom.js',
|
||||
'uri' => '/res/3afdac66/rsrc/js/javelin/core/Stratcom.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -1053,7 +1097,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'javelin-tokenizer' =>
|
||||
array(
|
||||
'uri' => '/res/1b1c2148/rsrc/js/javelin/lib/control/tokenizer/Tokenizer.js',
|
||||
'uri' => '/res/2b91543e/rsrc/js/javelin/lib/control/tokenizer/Tokenizer.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -1129,7 +1173,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'javelin-typeahead-source' =>
|
||||
array(
|
||||
'uri' => '/res/8606f519/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadSource.js',
|
||||
'uri' => '/res/e99c0c1d/rsrc/js/javelin/lib/control/typeahead/source/TypeaheadSource.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -1163,7 +1207,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'javelin-vector' =>
|
||||
array(
|
||||
'uri' => '/res/50535cb8/rsrc/js/javelin/lib/Vector.js',
|
||||
'uri' => '/res/f240bdb3/rsrc/js/javelin/lib/Vector.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -1252,6 +1296,15 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/css/application/maniphest/task-detail.css',
|
||||
),
|
||||
'maniphest-batch-editor' =>
|
||||
array(
|
||||
'uri' => '/res/fb15d744/rsrc/css/application/maniphest/batch-editor.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
'disk' => '/rsrc/css/application/maniphest/batch-editor.css',
|
||||
),
|
||||
'maniphest-task-edit-css' =>
|
||||
array(
|
||||
'uri' => '/res/68c7863e/rsrc/css/application/maniphest/task-edit.css',
|
||||
|
@ -1263,7 +1316,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'maniphest-task-summary-css' =>
|
||||
array(
|
||||
'uri' => '/res/14cb4b5d/rsrc/css/application/maniphest/task-summary.css',
|
||||
'uri' => '/res/7c52d502/rsrc/css/application/maniphest/task-summary.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -1272,7 +1325,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'maniphest-transaction-detail-css' =>
|
||||
array(
|
||||
'uri' => '/res/552bb734/rsrc/css/application/maniphest/transaction-detail.css',
|
||||
'uri' => '/res/24e5862f/rsrc/css/application/maniphest/transaction-detail.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -1332,7 +1385,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'phabricator-chatlog-css' =>
|
||||
array(
|
||||
'uri' => '/res/a5aa9eef/rsrc/css/application/chatlog/chatlog.css',
|
||||
'uri' => '/res/f674f526/rsrc/css/application/chatlog/chatlog.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -1478,6 +1531,20 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/css/application/objectselector/object-selector.css',
|
||||
),
|
||||
'phabricator-paste-file-upload' =>
|
||||
array(
|
||||
'uri' => '/res/cdc939bd/rsrc/js/application/core/PasteFileUpload.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-install',
|
||||
1 => 'javelin-util',
|
||||
2 => 'javelin-request',
|
||||
3 => 'javelin-dom',
|
||||
4 => 'javelin-uri',
|
||||
),
|
||||
'disk' => '/rsrc/js/application/core/PasteFileUpload.js',
|
||||
),
|
||||
'phabricator-prefab' =>
|
||||
array(
|
||||
'uri' => '/res/5784a112/rsrc/js/application/core/Prefab.js',
|
||||
|
@ -1510,24 +1577,13 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'phabricator-remarkup-css' =>
|
||||
array(
|
||||
'uri' => '/res/39f358b8/rsrc/css/core/remarkup.css',
|
||||
'uri' => '/res/02e0f11a/rsrc/css/core/remarkup.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
'disk' => '/rsrc/css/core/remarkup.css',
|
||||
),
|
||||
0 =>
|
||||
array(
|
||||
'uri' => '/res/b6096fdd/rsrc/js/javelin/lib/__tests__/URI.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-uri',
|
||||
1 => 'javelin-php-serializer',
|
||||
),
|
||||
'disk' => '/rsrc/js/javelin/lib/__tests__/URI.js',
|
||||
),
|
||||
'phabricator-search-results-css' =>
|
||||
array(
|
||||
'uri' => '/res/f8a86e27/rsrc/css/application/search/search-results.css',
|
||||
|
@ -1558,15 +1614,35 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/css/application/slowvote/slowvote.css',
|
||||
),
|
||||
0 =>
|
||||
array(
|
||||
'uri' => '/res/b6096fdd/rsrc/js/javelin/lib/__tests__/URI.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-uri',
|
||||
1 => 'javelin-php-serializer',
|
||||
),
|
||||
'disk' => '/rsrc/js/javelin/lib/__tests__/URI.js',
|
||||
),
|
||||
'phabricator-standard-page-view' =>
|
||||
array(
|
||||
'uri' => '/res/ec5acaed/rsrc/css/application/base/standard-page-view.css',
|
||||
'uri' => '/res/7e09bbfc/rsrc/css/application/base/standard-page-view.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
'disk' => '/rsrc/css/application/base/standard-page-view.css',
|
||||
),
|
||||
'phabricator-transaction-view-css' =>
|
||||
array(
|
||||
'uri' => '/res/731959fb/rsrc/css/aphront/transaction.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
'disk' => '/rsrc/css/aphront/transaction.css',
|
||||
),
|
||||
'phabricator-ui-example-css' =>
|
||||
array(
|
||||
'uri' => '/res/0cef078b/rsrc/css/application/uiexample/example.css',
|
||||
|
@ -1736,6 +1812,33 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/css/application/projects/project-edit.css',
|
||||
),
|
||||
'raphael-core' =>
|
||||
array(
|
||||
'uri' => '/res/bae05d27/rsrc/js/raphael/raphael.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
'disk' => '/rsrc/js/raphael/raphael.js',
|
||||
),
|
||||
'raphael-g' =>
|
||||
array(
|
||||
'uri' => '/res/8bbdbea8/rsrc/js/raphael/g.raphael.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
'disk' => '/rsrc/js/raphael/g.raphael.js',
|
||||
),
|
||||
'raphael-g-line' =>
|
||||
array(
|
||||
'uri' => '/res/54504ae4/rsrc/js/raphael/g.raphael.line.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
'disk' => '/rsrc/js/raphael/g.raphael.line.js',
|
||||
),
|
||||
'syntax-highlighting-css' =>
|
||||
array(
|
||||
'uri' => '/res/5669beb6/rsrc/css/core/syntax.css',
|
||||
|
@ -1748,17 +1851,70 @@ celerity_register_resource_map(array(
|
|||
), array(
|
||||
'packages' =>
|
||||
array(
|
||||
'03ef179e' =>
|
||||
'080edee4' =>
|
||||
array(
|
||||
'name' => 'typeahead.pkg.js',
|
||||
'symbols' =>
|
||||
array(
|
||||
0 => 'javelin-typeahead',
|
||||
1 => 'javelin-typeahead-normalizer',
|
||||
2 => 'javelin-typeahead-source',
|
||||
3 => 'javelin-typeahead-preloaded-source',
|
||||
4 => 'javelin-typeahead-ondemand-source',
|
||||
5 => 'javelin-tokenizer',
|
||||
6 => 'javelin-behavior-aphront-basic-tokenizer',
|
||||
),
|
||||
'uri' => '/res/pkg/080edee4/typeahead.pkg.js',
|
||||
'type' => 'js',
|
||||
),
|
||||
'46547a92' =>
|
||||
array(
|
||||
'name' => 'core.pkg.js',
|
||||
'symbols' =>
|
||||
array(
|
||||
0 => 'javelin-mask',
|
||||
1 => 'javelin-workflow',
|
||||
2 => 'javelin-behavior-workflow',
|
||||
3 => 'javelin-behavior-aphront-form-disable-on-submit',
|
||||
4 => 'phabricator-keyboard-shortcut-manager',
|
||||
5 => 'phabricator-keyboard-shortcut',
|
||||
6 => 'javelin-behavior-phabricator-keyboard-shortcuts',
|
||||
7 => 'javelin-behavior-refresh-csrf',
|
||||
8 => 'javelin-behavior-phabricator-watch-anchor',
|
||||
),
|
||||
'uri' => '/res/pkg/46547a92/core.pkg.js',
|
||||
'type' => 'js',
|
||||
),
|
||||
'4fbae2af' =>
|
||||
array(
|
||||
'name' => 'javelin.pkg.js',
|
||||
'symbols' =>
|
||||
array(
|
||||
0 => 'javelin-util',
|
||||
1 => 'javelin-install',
|
||||
2 => 'javelin-event',
|
||||
3 => 'javelin-stratcom',
|
||||
4 => 'javelin-behavior',
|
||||
5 => 'javelin-request',
|
||||
6 => 'javelin-vector',
|
||||
7 => 'javelin-dom',
|
||||
8 => 'javelin-json',
|
||||
9 => 'javelin-uri',
|
||||
),
|
||||
'uri' => '/res/pkg/4fbae2af/javelin.pkg.js',
|
||||
'type' => 'js',
|
||||
),
|
||||
'61f9d480' =>
|
||||
array(
|
||||
'name' => 'diffusion.pkg.css',
|
||||
'symbols' =>
|
||||
array(
|
||||
0 => 'diffusion-commit-view-css',
|
||||
),
|
||||
'uri' => '/res/pkg/03ef179e/diffusion.pkg.css',
|
||||
'uri' => '/res/pkg/61f9d480/diffusion.pkg.css',
|
||||
'type' => 'css',
|
||||
),
|
||||
'2729c1c6' =>
|
||||
'6a6def05' =>
|
||||
array(
|
||||
'name' => 'core.pkg.css',
|
||||
'symbols' =>
|
||||
|
@ -1779,44 +1935,10 @@ celerity_register_resource_map(array(
|
|||
13 => 'phabricator-remarkup-css',
|
||||
14 => 'syntax-highlighting-css',
|
||||
),
|
||||
'uri' => '/res/pkg/2729c1c6/core.pkg.css',
|
||||
'uri' => '/res/pkg/6a6def05/core.pkg.css',
|
||||
'type' => 'css',
|
||||
),
|
||||
'46547a92' =>
|
||||
array(
|
||||
'name' => 'core.pkg.js',
|
||||
'symbols' =>
|
||||
array(
|
||||
0 => 'javelin-mask',
|
||||
1 => 'javelin-workflow',
|
||||
2 => 'javelin-behavior-workflow',
|
||||
3 => 'javelin-behavior-aphront-form-disable-on-submit',
|
||||
4 => 'phabricator-keyboard-shortcut-manager',
|
||||
5 => 'phabricator-keyboard-shortcut',
|
||||
6 => 'javelin-behavior-phabricator-keyboard-shortcuts',
|
||||
7 => 'javelin-behavior-refresh-csrf',
|
||||
8 => 'javelin-behavior-phabricator-watch-anchor',
|
||||
),
|
||||
'uri' => '/res/pkg/46547a92/core.pkg.js',
|
||||
'type' => 'js',
|
||||
),
|
||||
'540effd7' =>
|
||||
array(
|
||||
'name' => 'typeahead.pkg.js',
|
||||
'symbols' =>
|
||||
array(
|
||||
0 => 'javelin-typeahead',
|
||||
1 => 'javelin-typeahead-normalizer',
|
||||
2 => 'javelin-typeahead-source',
|
||||
3 => 'javelin-typeahead-preloaded-source',
|
||||
4 => 'javelin-typeahead-ondemand-source',
|
||||
5 => 'javelin-tokenizer',
|
||||
6 => 'javelin-behavior-aphront-basic-tokenizer',
|
||||
),
|
||||
'uri' => '/res/pkg/540effd7/typeahead.pkg.js',
|
||||
'type' => 'js',
|
||||
),
|
||||
'80580cea' =>
|
||||
'8152415f' =>
|
||||
array(
|
||||
'name' => 'differential.pkg.css',
|
||||
'symbols' =>
|
||||
|
@ -1834,29 +1956,10 @@ celerity_register_resource_map(array(
|
|||
10 => 'phabricator-content-source-view-css',
|
||||
11 => 'differential-local-commits-view-css',
|
||||
),
|
||||
'uri' => '/res/pkg/80580cea/differential.pkg.css',
|
||||
'uri' => '/res/pkg/8152415f/differential.pkg.css',
|
||||
'type' => 'css',
|
||||
),
|
||||
'b164acea' =>
|
||||
array(
|
||||
'name' => 'javelin.pkg.js',
|
||||
'symbols' =>
|
||||
array(
|
||||
0 => 'javelin-util',
|
||||
1 => 'javelin-install',
|
||||
2 => 'javelin-event',
|
||||
3 => 'javelin-stratcom',
|
||||
4 => 'javelin-behavior',
|
||||
5 => 'javelin-request',
|
||||
6 => 'javelin-vector',
|
||||
7 => 'javelin-dom',
|
||||
8 => 'javelin-json',
|
||||
9 => 'javelin-uri',
|
||||
),
|
||||
'uri' => '/res/pkg/b164acea/javelin.pkg.js',
|
||||
'type' => 'js',
|
||||
),
|
||||
'ef420ead' =>
|
||||
'c8aaade8' =>
|
||||
array(
|
||||
'name' => 'differential.pkg.js',
|
||||
'symbols' =>
|
||||
|
@ -1877,80 +1980,80 @@ celerity_register_resource_map(array(
|
|||
13 => 'javelin-behavior-phabricator-object-selector',
|
||||
14 => 'differential-inline-comment-editor',
|
||||
),
|
||||
'uri' => '/res/pkg/ef420ead/differential.pkg.js',
|
||||
'uri' => '/res/pkg/c8aaade8/differential.pkg.js',
|
||||
'type' => 'js',
|
||||
),
|
||||
),
|
||||
'reverse' =>
|
||||
array(
|
||||
'aphront-crumbs-view-css' => '2729c1c6',
|
||||
'aphront-dialog-view-css' => '2729c1c6',
|
||||
'aphront-form-view-css' => '2729c1c6',
|
||||
'aphront-headsup-action-list-view-css' => '80580cea',
|
||||
'aphront-list-filter-view-css' => '2729c1c6',
|
||||
'aphront-panel-view-css' => '2729c1c6',
|
||||
'aphront-side-nav-view-css' => '2729c1c6',
|
||||
'aphront-table-view-css' => '2729c1c6',
|
||||
'aphront-tokenizer-control-css' => '2729c1c6',
|
||||
'aphront-typeahead-control-css' => '2729c1c6',
|
||||
'differential-changeset-view-css' => '80580cea',
|
||||
'differential-core-view-css' => '80580cea',
|
||||
'differential-inline-comment-editor' => 'ef420ead',
|
||||
'differential-local-commits-view-css' => '80580cea',
|
||||
'differential-revision-add-comment-css' => '80580cea',
|
||||
'differential-revision-comment-css' => '80580cea',
|
||||
'differential-revision-comment-list-css' => '80580cea',
|
||||
'differential-revision-detail-css' => '80580cea',
|
||||
'differential-revision-history-css' => '80580cea',
|
||||
'differential-table-of-contents-css' => '80580cea',
|
||||
'diffusion-commit-view-css' => '03ef179e',
|
||||
'javelin-behavior' => 'b164acea',
|
||||
'javelin-behavior-aphront-basic-tokenizer' => '540effd7',
|
||||
'javelin-behavior-aphront-drag-and-drop' => 'ef420ead',
|
||||
'javelin-behavior-aphront-drag-and-drop-textarea' => 'ef420ead',
|
||||
'aphront-crumbs-view-css' => '6a6def05',
|
||||
'aphront-dialog-view-css' => '6a6def05',
|
||||
'aphront-form-view-css' => '6a6def05',
|
||||
'aphront-headsup-action-list-view-css' => '8152415f',
|
||||
'aphront-list-filter-view-css' => '6a6def05',
|
||||
'aphront-panel-view-css' => '6a6def05',
|
||||
'aphront-side-nav-view-css' => '6a6def05',
|
||||
'aphront-table-view-css' => '6a6def05',
|
||||
'aphront-tokenizer-control-css' => '6a6def05',
|
||||
'aphront-typeahead-control-css' => '6a6def05',
|
||||
'differential-changeset-view-css' => '8152415f',
|
||||
'differential-core-view-css' => '8152415f',
|
||||
'differential-inline-comment-editor' => 'c8aaade8',
|
||||
'differential-local-commits-view-css' => '8152415f',
|
||||
'differential-revision-add-comment-css' => '8152415f',
|
||||
'differential-revision-comment-css' => '8152415f',
|
||||
'differential-revision-comment-list-css' => '8152415f',
|
||||
'differential-revision-detail-css' => '8152415f',
|
||||
'differential-revision-history-css' => '8152415f',
|
||||
'differential-table-of-contents-css' => '8152415f',
|
||||
'diffusion-commit-view-css' => '61f9d480',
|
||||
'javelin-behavior' => '4fbae2af',
|
||||
'javelin-behavior-aphront-basic-tokenizer' => '080edee4',
|
||||
'javelin-behavior-aphront-drag-and-drop' => 'c8aaade8',
|
||||
'javelin-behavior-aphront-drag-and-drop-textarea' => 'c8aaade8',
|
||||
'javelin-behavior-aphront-form-disable-on-submit' => '46547a92',
|
||||
'javelin-behavior-differential-accept-with-errors' => 'ef420ead',
|
||||
'javelin-behavior-differential-add-reviewers-and-ccs' => 'ef420ead',
|
||||
'javelin-behavior-differential-comment-jump' => 'ef420ead',
|
||||
'javelin-behavior-differential-diff-radios' => 'ef420ead',
|
||||
'javelin-behavior-differential-edit-inline-comments' => 'ef420ead',
|
||||
'javelin-behavior-differential-feedback-preview' => 'ef420ead',
|
||||
'javelin-behavior-differential-keyboard-navigation' => 'ef420ead',
|
||||
'javelin-behavior-differential-populate' => 'ef420ead',
|
||||
'javelin-behavior-differential-show-more' => 'ef420ead',
|
||||
'javelin-behavior-differential-accept-with-errors' => 'c8aaade8',
|
||||
'javelin-behavior-differential-add-reviewers-and-ccs' => 'c8aaade8',
|
||||
'javelin-behavior-differential-comment-jump' => 'c8aaade8',
|
||||
'javelin-behavior-differential-diff-radios' => 'c8aaade8',
|
||||
'javelin-behavior-differential-edit-inline-comments' => 'c8aaade8',
|
||||
'javelin-behavior-differential-feedback-preview' => 'c8aaade8',
|
||||
'javelin-behavior-differential-keyboard-navigation' => 'c8aaade8',
|
||||
'javelin-behavior-differential-populate' => 'c8aaade8',
|
||||
'javelin-behavior-differential-show-more' => 'c8aaade8',
|
||||
'javelin-behavior-phabricator-keyboard-shortcuts' => '46547a92',
|
||||
'javelin-behavior-phabricator-object-selector' => 'ef420ead',
|
||||
'javelin-behavior-phabricator-object-selector' => 'c8aaade8',
|
||||
'javelin-behavior-phabricator-watch-anchor' => '46547a92',
|
||||
'javelin-behavior-refresh-csrf' => '46547a92',
|
||||
'javelin-behavior-workflow' => '46547a92',
|
||||
'javelin-dom' => 'b164acea',
|
||||
'javelin-event' => 'b164acea',
|
||||
'javelin-install' => 'b164acea',
|
||||
'javelin-json' => 'b164acea',
|
||||
'javelin-dom' => '4fbae2af',
|
||||
'javelin-event' => '4fbae2af',
|
||||
'javelin-install' => '4fbae2af',
|
||||
'javelin-json' => '4fbae2af',
|
||||
'javelin-mask' => '46547a92',
|
||||
'javelin-request' => 'b164acea',
|
||||
'javelin-stratcom' => 'b164acea',
|
||||
'javelin-tokenizer' => '540effd7',
|
||||
'javelin-typeahead' => '540effd7',
|
||||
'javelin-typeahead-normalizer' => '540effd7',
|
||||
'javelin-typeahead-ondemand-source' => '540effd7',
|
||||
'javelin-typeahead-preloaded-source' => '540effd7',
|
||||
'javelin-typeahead-source' => '540effd7',
|
||||
'javelin-uri' => 'b164acea',
|
||||
'javelin-util' => 'b164acea',
|
||||
'javelin-vector' => 'b164acea',
|
||||
'javelin-request' => '4fbae2af',
|
||||
'javelin-stratcom' => '4fbae2af',
|
||||
'javelin-tokenizer' => '080edee4',
|
||||
'javelin-typeahead' => '080edee4',
|
||||
'javelin-typeahead-normalizer' => '080edee4',
|
||||
'javelin-typeahead-ondemand-source' => '080edee4',
|
||||
'javelin-typeahead-preloaded-source' => '080edee4',
|
||||
'javelin-typeahead-source' => '080edee4',
|
||||
'javelin-uri' => '4fbae2af',
|
||||
'javelin-util' => '4fbae2af',
|
||||
'javelin-vector' => '4fbae2af',
|
||||
'javelin-workflow' => '46547a92',
|
||||
'phabricator-content-source-view-css' => '80580cea',
|
||||
'phabricator-core-buttons-css' => '2729c1c6',
|
||||
'phabricator-core-css' => '2729c1c6',
|
||||
'phabricator-directory-css' => '2729c1c6',
|
||||
'phabricator-drag-and-drop-file-upload' => 'ef420ead',
|
||||
'phabricator-content-source-view-css' => '8152415f',
|
||||
'phabricator-core-buttons-css' => '6a6def05',
|
||||
'phabricator-core-css' => '6a6def05',
|
||||
'phabricator-directory-css' => '6a6def05',
|
||||
'phabricator-drag-and-drop-file-upload' => 'c8aaade8',
|
||||
'phabricator-keyboard-shortcut' => '46547a92',
|
||||
'phabricator-keyboard-shortcut-manager' => '46547a92',
|
||||
'phabricator-object-selector-css' => '80580cea',
|
||||
'phabricator-remarkup-css' => '2729c1c6',
|
||||
'phabricator-shaped-request' => 'ef420ead',
|
||||
'phabricator-standard-page-view' => '2729c1c6',
|
||||
'syntax-highlighting-css' => '2729c1c6',
|
||||
'phabricator-object-selector-css' => '8152415f',
|
||||
'phabricator-remarkup-css' => '6a6def05',
|
||||
'phabricator-shaped-request' => 'c8aaade8',
|
||||
'phabricator-standard-page-view' => '6a6def05',
|
||||
'syntax-highlighting-css' => '6a6def05',
|
||||
),
|
||||
));
|
||||
|
|
|
@ -204,6 +204,8 @@ phutil_register_library_map(array(
|
|||
'DifferentialCommitsFieldSpecification' => 'applications/differential/field/specification/commits',
|
||||
'DifferentialController' => 'applications/differential/controller/base',
|
||||
'DifferentialDAO' => 'applications/differential/storage/base',
|
||||
'DifferentialDateCreatedFieldSpecification' => 'applications/differential/field/specification/datecreated',
|
||||
'DifferentialDateModifiedFieldSpecification' => 'applications/differential/field/specification/datemodified',
|
||||
'DifferentialDefaultFieldSelector' => 'applications/differential/field/selector/default',
|
||||
'DifferentialDependenciesFieldSpecification' => 'applications/differential/field/specification/dependencies',
|
||||
'DifferentialDiff' => 'applications/differential/storage/diff',
|
||||
|
@ -256,6 +258,8 @@ phutil_register_library_map(array(
|
|||
'DifferentialRevisionListData' => 'applications/differential/data/revisionlist',
|
||||
'DifferentialRevisionListView' => 'applications/differential/view/revisionlist',
|
||||
'DifferentialRevisionQuery' => 'applications/differential/query/revision',
|
||||
'DifferentialRevisionStatsController' => 'applications/differential/controller/revisionstats',
|
||||
'DifferentialRevisionStatsView' => 'applications/differential/view/revisionstats',
|
||||
'DifferentialRevisionStatusFieldSpecification' => 'applications/differential/field/specification/revisionstatus',
|
||||
'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/revisionupdatehistory',
|
||||
'DifferentialRevisionViewController' => 'applications/differential/controller/revisionview',
|
||||
|
@ -275,6 +279,8 @@ phutil_register_library_map(array(
|
|||
'DiffusionBrowseQuery' => 'applications/diffusion/query/browse/base',
|
||||
'DiffusionBrowseTableView' => 'applications/diffusion/view/browsetable',
|
||||
'DiffusionChangeController' => 'applications/diffusion/controller/change',
|
||||
'DiffusionCommentListView' => 'applications/diffusion/view/commentlist',
|
||||
'DiffusionCommentView' => 'applications/diffusion/view/comment',
|
||||
'DiffusionCommitChangeTableView' => 'applications/diffusion/view/commitchangetable',
|
||||
'DiffusionCommitController' => 'applications/diffusion/controller/commit',
|
||||
'DiffusionCommitListController' => 'applications/diffusion/controller/commitlist',
|
||||
|
@ -399,6 +405,7 @@ phutil_register_library_map(array(
|
|||
'ManiphestAuxiliaryFieldSpecification' => 'applications/maniphest/auxiliaryfield/base',
|
||||
'ManiphestAuxiliaryFieldTypeException' => 'applications/maniphest/auxiliaryfield/typeexception',
|
||||
'ManiphestAuxiliaryFieldValidationException' => 'applications/maniphest/auxiliaryfield/validationexception',
|
||||
'ManiphestBatchEditController' => 'applications/maniphest/controller/batch',
|
||||
'ManiphestConstants' => 'applications/maniphest/constants/base',
|
||||
'ManiphestController' => 'applications/maniphest/controller/base',
|
||||
'ManiphestDAO' => 'applications/maniphest/storage/base',
|
||||
|
@ -430,12 +437,19 @@ phutil_register_library_map(array(
|
|||
'ManiphestTransactionSaveController' => 'applications/maniphest/controller/transactionsave',
|
||||
'ManiphestTransactionType' => 'applications/maniphest/constants/transactiontype',
|
||||
'ManiphestView' => 'applications/maniphest/view/base',
|
||||
'MetaMTAConstants' => 'applications/metamta/constants/base',
|
||||
'MetaMTANotificationType' => 'applications/metamta/constants/notificationtype',
|
||||
'Phabricator404Controller' => 'applications/base/controller/404',
|
||||
'PhabricatorAuditActionConstants' => 'applications/audit/constants/action',
|
||||
'PhabricatorAuditAddCommentController' => 'applications/audit/controller/addcomment',
|
||||
'PhabricatorAuditComment' => 'applications/audit/storage/auditcomment',
|
||||
'PhabricatorAuditCommentEditor' => 'applications/audit/editor/comment',
|
||||
'PhabricatorAuditController' => 'applications/audit/controller/base',
|
||||
'PhabricatorAuditDAO' => 'applications/audit/storage/base',
|
||||
'PhabricatorAuditEditController' => 'applications/audit/controller/edit',
|
||||
'PhabricatorAuditListController' => 'applications/audit/controller/list',
|
||||
'PhabricatorAuditListView' => 'applications/audit/view/list',
|
||||
'PhabricatorAuditQuery' => 'applications/audit/query/audit',
|
||||
'PhabricatorAuditStatusConstants' => 'applications/audit/constants/status',
|
||||
'PhabricatorAuthController' => 'applications/auth/controller/base',
|
||||
'PhabricatorCalendarBrowseController' => 'applications/calendar/controller/browse',
|
||||
|
@ -559,6 +573,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorIRCMessage' => 'infrastructure/daemon/irc/message',
|
||||
'PhabricatorIRCObjectNameHandler' => 'infrastructure/daemon/irc/handler/objectname',
|
||||
'PhabricatorIRCProtocolHandler' => 'infrastructure/daemon/irc/handler/protocol',
|
||||
'PhabricatorIRCWhatsNewHandler' => 'infrastructure/daemon/irc/handler/whatsnew',
|
||||
'PhabricatorImageTransformer' => 'applications/files/transform',
|
||||
'PhabricatorInfrastructureTestCase' => 'infrastructure/__tests__',
|
||||
'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/javelin',
|
||||
|
@ -595,6 +610,16 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMetaMTASendGridReceiveController' => 'applications/metamta/controller/sendgridreceive',
|
||||
'PhabricatorMetaMTAViewController' => 'applications/metamta/controller/view',
|
||||
'PhabricatorMySQLFileStorageEngine' => 'applications/files/engine/mysql',
|
||||
'PhabricatorOAuthClientAuthorization' => 'applications/oauthserver/storage/clientauthorization',
|
||||
'PhabricatorOAuthClientAuthorizationBaseController' => 'applications/oauthserver/controller/clientauthorization/base',
|
||||
'PhabricatorOAuthClientAuthorizationDeleteController' => 'applications/oauthserver/controller/clientauthorization/delete',
|
||||
'PhabricatorOAuthClientAuthorizationEditController' => 'applications/oauthserver/controller/clientauthorization/edit',
|
||||
'PhabricatorOAuthClientAuthorizationListController' => 'applications/oauthserver/controller/clientauthorization/list',
|
||||
'PhabricatorOAuthClientBaseController' => 'applications/oauthserver/controller/client/base',
|
||||
'PhabricatorOAuthClientDeleteController' => 'applications/oauthserver/controller/client/delete',
|
||||
'PhabricatorOAuthClientEditController' => 'applications/oauthserver/controller/client/edit',
|
||||
'PhabricatorOAuthClientListController' => 'applications/oauthserver/controller/client/list',
|
||||
'PhabricatorOAuthClientViewController' => 'applications/oauthserver/controller/client/view',
|
||||
'PhabricatorOAuthDefaultRegistrationController' => 'applications/auth/controller/oauthregistration/default',
|
||||
'PhabricatorOAuthDiagnosticsController' => 'applications/auth/controller/oauthdiagnostics',
|
||||
'PhabricatorOAuthFailureView' => 'applications/auth/view/oauthfailure',
|
||||
|
@ -603,7 +628,19 @@ phutil_register_library_map(array(
|
|||
'PhabricatorOAuthProviderFacebook' => 'applications/auth/oauth/provider/facebook',
|
||||
'PhabricatorOAuthProviderGitHub' => 'applications/auth/oauth/provider/github',
|
||||
'PhabricatorOAuthProviderGoogle' => 'applications/auth/oauth/provider/google',
|
||||
'PhabricatorOAuthProviderPhabricator' => 'applications/auth/oauth/provider/phabricator',
|
||||
'PhabricatorOAuthRegistrationController' => 'applications/auth/controller/oauthregistration/base',
|
||||
'PhabricatorOAuthResponse' => 'applications/oauthserver/response',
|
||||
'PhabricatorOAuthServer' => 'applications/oauthserver/server',
|
||||
'PhabricatorOAuthServerAccessToken' => 'applications/oauthserver/storage/accesstoken',
|
||||
'PhabricatorOAuthServerAuthController' => 'applications/oauthserver/controller/auth',
|
||||
'PhabricatorOAuthServerAuthorizationCode' => 'applications/oauthserver/storage/authorizationcode',
|
||||
'PhabricatorOAuthServerClient' => 'applications/oauthserver/storage/client',
|
||||
'PhabricatorOAuthServerController' => 'applications/oauthserver/controller/base',
|
||||
'PhabricatorOAuthServerDAO' => 'applications/oauthserver/storage/base',
|
||||
'PhabricatorOAuthServerScope' => 'applications/oauthserver/scope',
|
||||
'PhabricatorOAuthServerTestController' => 'applications/oauthserver/controller/test',
|
||||
'PhabricatorOAuthServerTokenController' => 'applications/oauthserver/controller/token',
|
||||
'PhabricatorOAuthUnlinkController' => 'applications/auth/controller/unlink',
|
||||
'PhabricatorObjectAttachmentEditor' => 'applications/search/editor/attach',
|
||||
'PhabricatorObjectGraph' => 'applications/phid/graph',
|
||||
|
@ -653,6 +690,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectProfileController' => 'applications/project/controller/profile',
|
||||
'PhabricatorProjectProfileEditController' => 'applications/project/controller/profileedit',
|
||||
'PhabricatorProjectQuery' => 'applications/project/query/project',
|
||||
'PhabricatorProjectQueryUtil' => 'applications/project/query/util',
|
||||
'PhabricatorProjectStatus' => 'applications/project/constants/status',
|
||||
'PhabricatorProjectSubproject' => 'applications/project/storage/subproject',
|
||||
'PhabricatorProjectTransaction' => 'applications/project/storage/transaction',
|
||||
|
@ -760,6 +798,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorTimelineEventData' => 'infrastructure/daemon/timeline/storage/eventdata',
|
||||
'PhabricatorTimelineIterator' => 'infrastructure/daemon/timeline/cursor/iterator',
|
||||
'PhabricatorTimer' => 'applications/countdown/storage/timer',
|
||||
'PhabricatorTransactionView' => 'view/layout/transaction',
|
||||
'PhabricatorTransformedFile' => 'applications/files/storage/transformed',
|
||||
'PhabricatorTrivialTestCase' => 'infrastructure/testing/testcase/__tests__',
|
||||
'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/common',
|
||||
|
@ -1020,6 +1059,8 @@ phutil_register_library_map(array(
|
|||
'DifferentialCommitsFieldSpecification' => 'DifferentialFieldSpecification',
|
||||
'DifferentialController' => 'PhabricatorController',
|
||||
'DifferentialDAO' => 'PhabricatorLiskDAO',
|
||||
'DifferentialDateCreatedFieldSpecification' => 'DifferentialFieldSpecification',
|
||||
'DifferentialDateModifiedFieldSpecification' => 'DifferentialFieldSpecification',
|
||||
'DifferentialDefaultFieldSelector' => 'DifferentialFieldSelector',
|
||||
'DifferentialDependenciesFieldSpecification' => 'DifferentialFieldSpecification',
|
||||
'DifferentialDiff' => 'DifferentialDAO',
|
||||
|
@ -1058,6 +1099,8 @@ phutil_register_library_map(array(
|
|||
'DifferentialRevisionIDFieldSpecification' => 'DifferentialFieldSpecification',
|
||||
'DifferentialRevisionListController' => 'DifferentialController',
|
||||
'DifferentialRevisionListView' => 'AphrontView',
|
||||
'DifferentialRevisionStatsController' => 'DifferentialController',
|
||||
'DifferentialRevisionStatsView' => 'AphrontView',
|
||||
'DifferentialRevisionStatusFieldSpecification' => 'DifferentialFieldSpecification',
|
||||
'DifferentialRevisionUpdateHistoryView' => 'AphrontView',
|
||||
'DifferentialRevisionViewController' => 'DifferentialController',
|
||||
|
@ -1071,6 +1114,8 @@ phutil_register_library_map(array(
|
|||
'DiffusionBrowseFileController' => 'DiffusionController',
|
||||
'DiffusionBrowseTableView' => 'DiffusionView',
|
||||
'DiffusionChangeController' => 'DiffusionController',
|
||||
'DiffusionCommentListView' => 'AphrontView',
|
||||
'DiffusionCommentView' => 'AphrontView',
|
||||
'DiffusionCommitChangeTableView' => 'DiffusionView',
|
||||
'DiffusionCommitController' => 'DiffusionController',
|
||||
'DiffusionCommitListController' => 'DiffusionController',
|
||||
|
@ -1157,6 +1202,7 @@ phutil_register_library_map(array(
|
|||
'LiskIsolationTestDAO' => 'LiskDAO',
|
||||
'ManiphestAction' => 'PhrictionConstants',
|
||||
'ManiphestAuxiliaryFieldDefaultSpecification' => 'ManiphestAuxiliaryFieldSpecification',
|
||||
'ManiphestBatchEditController' => 'ManiphestController',
|
||||
'ManiphestController' => 'PhabricatorController',
|
||||
'ManiphestDAO' => 'PhabricatorLiskDAO',
|
||||
'ManiphestDefaultTaskExtensions' => 'ManiphestTaskExtensions',
|
||||
|
@ -1184,11 +1230,15 @@ phutil_register_library_map(array(
|
|||
'ManiphestTransactionSaveController' => 'ManiphestController',
|
||||
'ManiphestTransactionType' => 'ManiphestConstants',
|
||||
'ManiphestView' => 'AphrontView',
|
||||
'MetaMTANotificationType' => 'MetaMTAConstants',
|
||||
'Phabricator404Controller' => 'PhabricatorController',
|
||||
'PhabricatorAuditAddCommentController' => 'PhabricatorAuditController',
|
||||
'PhabricatorAuditComment' => 'PhabricatorAuditDAO',
|
||||
'PhabricatorAuditController' => 'PhabricatorController',
|
||||
'PhabricatorAuditDAO' => 'PhabricatorLiskDAO',
|
||||
'PhabricatorAuditEditController' => 'PhabricatorAuditController',
|
||||
'PhabricatorAuditListController' => 'PhabricatorAuditController',
|
||||
'PhabricatorAuditListView' => 'AphrontView',
|
||||
'PhabricatorAuthController' => 'PhabricatorController',
|
||||
'PhabricatorCalendarBrowseController' => 'PhabricatorCalendarController',
|
||||
'PhabricatorCalendarController' => 'PhabricatorController',
|
||||
|
@ -1291,6 +1341,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorIRCLogHandler' => 'PhabricatorIRCHandler',
|
||||
'PhabricatorIRCObjectNameHandler' => 'PhabricatorIRCHandler',
|
||||
'PhabricatorIRCProtocolHandler' => 'PhabricatorIRCHandler',
|
||||
'PhabricatorIRCWhatsNewHandler' => 'PhabricatorIRCHandler',
|
||||
'PhabricatorInfrastructureTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorJavelinLinter' => 'ArcanistLinter',
|
||||
'PhabricatorLintEngine' => 'PhutilLintEngine',
|
||||
|
@ -1321,6 +1372,16 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMetaMTASendGridReceiveController' => 'PhabricatorMetaMTAController',
|
||||
'PhabricatorMetaMTAViewController' => 'PhabricatorMetaMTAController',
|
||||
'PhabricatorMySQLFileStorageEngine' => 'PhabricatorFileStorageEngine',
|
||||
'PhabricatorOAuthClientAuthorization' => 'PhabricatorOAuthServerDAO',
|
||||
'PhabricatorOAuthClientAuthorizationBaseController' => 'PhabricatorOAuthServerController',
|
||||
'PhabricatorOAuthClientAuthorizationDeleteController' => 'PhabricatorOAuthClientAuthorizationBaseController',
|
||||
'PhabricatorOAuthClientAuthorizationEditController' => 'PhabricatorOAuthClientAuthorizationBaseController',
|
||||
'PhabricatorOAuthClientAuthorizationListController' => 'PhabricatorOAuthClientAuthorizationBaseController',
|
||||
'PhabricatorOAuthClientBaseController' => 'PhabricatorOAuthServerController',
|
||||
'PhabricatorOAuthClientDeleteController' => 'PhabricatorOAuthClientBaseController',
|
||||
'PhabricatorOAuthClientEditController' => 'PhabricatorOAuthClientBaseController',
|
||||
'PhabricatorOAuthClientListController' => 'PhabricatorOAuthClientBaseController',
|
||||
'PhabricatorOAuthClientViewController' => 'PhabricatorOAuthClientBaseController',
|
||||
'PhabricatorOAuthDefaultRegistrationController' => 'PhabricatorOAuthRegistrationController',
|
||||
'PhabricatorOAuthDiagnosticsController' => 'PhabricatorAuthController',
|
||||
'PhabricatorOAuthFailureView' => 'AphrontView',
|
||||
|
@ -1328,7 +1389,17 @@ phutil_register_library_map(array(
|
|||
'PhabricatorOAuthProviderFacebook' => 'PhabricatorOAuthProvider',
|
||||
'PhabricatorOAuthProviderGitHub' => 'PhabricatorOAuthProvider',
|
||||
'PhabricatorOAuthProviderGoogle' => 'PhabricatorOAuthProvider',
|
||||
'PhabricatorOAuthProviderPhabricator' => 'PhabricatorOAuthProvider',
|
||||
'PhabricatorOAuthRegistrationController' => 'PhabricatorAuthController',
|
||||
'PhabricatorOAuthResponse' => 'AphrontResponse',
|
||||
'PhabricatorOAuthServerAccessToken' => 'PhabricatorOAuthServerDAO',
|
||||
'PhabricatorOAuthServerAuthController' => 'PhabricatorAuthController',
|
||||
'PhabricatorOAuthServerAuthorizationCode' => 'PhabricatorOAuthServerDAO',
|
||||
'PhabricatorOAuthServerClient' => 'PhabricatorOAuthServerDAO',
|
||||
'PhabricatorOAuthServerController' => 'PhabricatorController',
|
||||
'PhabricatorOAuthServerDAO' => 'PhabricatorLiskDAO',
|
||||
'PhabricatorOAuthServerTestController' => 'PhabricatorOAuthServerController',
|
||||
'PhabricatorOAuthServerTokenController' => 'PhabricatorAuthController',
|
||||
'PhabricatorOAuthUnlinkController' => 'PhabricatorAuthController',
|
||||
'PhabricatorObjectGraph' => 'AbstractDirectedGraph',
|
||||
'PhabricatorObjectHandleStatus' => 'PhabricatorObjectHandleConstants',
|
||||
|
@ -1460,6 +1531,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorTimelineEvent' => 'PhabricatorTimelineDAO',
|
||||
'PhabricatorTimelineEventData' => 'PhabricatorTimelineDAO',
|
||||
'PhabricatorTimer' => 'PhabricatorCountdownDAO',
|
||||
'PhabricatorTransactionView' => 'AphrontView',
|
||||
'PhabricatorTransformedFile' => 'PhabricatorFileDAO',
|
||||
'PhabricatorTrivialTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController',
|
||||
|
|
|
@ -32,8 +32,13 @@ class AphrontDefaultApplicationConfiguration
|
|||
|
||||
public function getURIMap() {
|
||||
return $this->getResourceURIMapRules() + array(
|
||||
'/(?:(?P<filter>(?:feed|jump))/)?$' =>
|
||||
'/(?:(?P<filter>jump)/)?$' =>
|
||||
'PhabricatorDirectoryMainController',
|
||||
'/(?:(?P<filter>feed)/)' => array(
|
||||
'public/$' => 'PhabricatorFeedPublicStreamController',
|
||||
'(?:(?P<subfilter>[^/]+)/)?$' =>
|
||||
'PhabricatorDirectoryMainController',
|
||||
),
|
||||
'/directory/' => array(
|
||||
'(?P<id>\d+)/$'
|
||||
=> 'PhabricatorDirectoryCategoryViewController',
|
||||
|
@ -96,6 +101,7 @@ class AphrontDefaultApplicationConfiguration
|
|||
'/differential/' => array(
|
||||
'$' => 'DifferentialRevisionListController',
|
||||
'filter/(?P<filter>\w+)/$' => 'DifferentialRevisionListController',
|
||||
'stats/(?P<filter>\w+)/$' => 'DifferentialRevisionStatsController',
|
||||
'diff/' => array(
|
||||
'(?P<id>\d+)/$' => 'DifferentialDiffViewController',
|
||||
'create/$' => 'DifferentialDiffCreateController',
|
||||
|
@ -151,6 +157,27 @@ class AphrontDefaultApplicationConfiguration
|
|||
),
|
||||
),
|
||||
|
||||
'/oauthserver/' => array(
|
||||
'auth/' => 'PhabricatorOAuthServerAuthController',
|
||||
'test/' => 'PhabricatorOAuthServerTestController',
|
||||
'token/' => 'PhabricatorOAuthServerTokenController',
|
||||
'clientauthorization/' => array(
|
||||
'$' => 'PhabricatorOAuthClientAuthorizationListController',
|
||||
'delete/(?P<phid>[^/]+)/' =>
|
||||
'PhabricatorOAuthClientAuthorizationDeleteController',
|
||||
'edit/(?P<phid>[^/]+)/' =>
|
||||
'PhabricatorOAuthClientAuthorizationEditController',
|
||||
),
|
||||
'client/' => array(
|
||||
'$' => 'PhabricatorOAuthClientListController',
|
||||
'create/$' => 'PhabricatorOAuthClientEditController',
|
||||
'delete/(?P<phid>[^/]+)/$' =>
|
||||
'PhabricatorOAuthClientDeleteController',
|
||||
'edit/(?P<phid>[^/]+)/$' => 'PhabricatorOAuthClientEditController',
|
||||
'view/(?P<phid>[^/]+)/$' => 'PhabricatorOAuthClientViewController',
|
||||
),
|
||||
),
|
||||
|
||||
'/xhprof/' => array(
|
||||
'profile/(?P<phid>[^/]+)/$' => 'PhabricatorXHProfProfileController',
|
||||
),
|
||||
|
@ -165,6 +192,7 @@ class AphrontDefaultApplicationConfiguration
|
|||
'$' => 'ManiphestTaskListController',
|
||||
'view/(?P<view>\w+)/$' => 'ManiphestTaskListController',
|
||||
'report/(?:(?P<view>\w+)/)?$' => 'ManiphestReportController',
|
||||
'batch/$' => 'ManiphestBatchEditController',
|
||||
'task/' => array(
|
||||
'create/$' => 'ManiphestTaskEditController',
|
||||
'edit/(?P<id>\d+)/$' => 'ManiphestTaskEditController',
|
||||
|
@ -318,8 +346,11 @@ class AphrontDefaultApplicationConfiguration
|
|||
),
|
||||
|
||||
'/audit/' => array(
|
||||
'$' => 'PhabricatorAuditEditController',
|
||||
'$' => 'PhabricatorAuditListController',
|
||||
'view/(?P<filter>[^/]+)/$' => 'PhabricatorAuditListController',
|
||||
|
||||
'edit/$' => 'PhabricatorAuditEditController',
|
||||
'addcomment/$' => 'PhabricatorAuditAddCommentController',
|
||||
),
|
||||
|
||||
'/xhpast/' => array(
|
||||
|
@ -359,8 +390,6 @@ class AphrontDefaultApplicationConfiguration
|
|||
=> 'PhabricatorCountdownDeleteController'
|
||||
),
|
||||
|
||||
'/feed/public/$' => 'PhabricatorFeedPublicStreamController',
|
||||
|
||||
'/V(?P<id>\d+)$' => 'PhabricatorSlowvotePollController',
|
||||
'/vote/' => array(
|
||||
'(?:view/(?P<view>\w+)/)?$' => 'PhabricatorSlowvoteListController',
|
||||
|
|
|
@ -21,15 +21,28 @@
|
|||
*/
|
||||
class Aphront403Response extends AphrontWebpageResponse {
|
||||
|
||||
private $forbiddenText;
|
||||
public function setForbiddenText($text) {
|
||||
$this->forbiddenText = $text;
|
||||
return $this;
|
||||
}
|
||||
private function getForbiddenText() {
|
||||
return $this->forbiddenText;
|
||||
}
|
||||
|
||||
public function getHTTPResponseCode() {
|
||||
return 403;
|
||||
}
|
||||
|
||||
public function buildResponseString() {
|
||||
$forbidden_text = $this->getForbiddenText();
|
||||
if (!$forbidden_text) {
|
||||
$forbidden_text =
|
||||
'You do not have privileges to access the requested page.';
|
||||
}
|
||||
$failure = new AphrontRequestFailureView();
|
||||
$failure->setHeader('403 Forbidden');
|
||||
$failure->appendChild(
|
||||
'<p>You do not have privileges to access the requested page.</p>');
|
||||
$failure->appendChild('<p>'.$forbidden_text.'</p>');
|
||||
|
||||
$view = new PhabricatorStandardPageView();
|
||||
$view->setTitle('403 Forbidden');
|
||||
|
|
|
@ -35,9 +35,8 @@ final class AphrontAjaxResponse extends AphrontResponse {
|
|||
$this->content,
|
||||
$this->error);
|
||||
|
||||
return $this->encodeJSONForHTTPResponse(
|
||||
$object,
|
||||
$use_javelin_shield = true);
|
||||
$response_json = $this->encodeJSONForHTTPResponse($object);
|
||||
return $this->addJSONShield($response_json, $use_javelin_shield = true);
|
||||
}
|
||||
|
||||
public function getHeaders() {
|
||||
|
|
|
@ -70,9 +70,7 @@ abstract class AphrontResponse {
|
|||
return $this;
|
||||
}
|
||||
|
||||
protected function encodeJSONForHTTPResponse(
|
||||
array $object,
|
||||
$use_javelin_shield) {
|
||||
protected function encodeJSONForHTTPResponse(array $object) {
|
||||
|
||||
$response = json_encode($object);
|
||||
|
||||
|
@ -84,6 +82,11 @@ abstract class AphrontResponse {
|
|||
array('\u003c', '\u003e'),
|
||||
$response);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function addJSONShield($json_response, $use_javelin_shield) {
|
||||
|
||||
// Add a shield to prevent "JSON Hijacking" attacks where an attacker
|
||||
// requests a JSON response using a normal <script /> tag and then uses
|
||||
// Object.prototype.__defineSetter__() or similar to read response data.
|
||||
|
@ -96,7 +99,7 @@ abstract class AphrontResponse {
|
|||
? 'for (;;);'
|
||||
: 'for(;;);';
|
||||
|
||||
$response = $shield.$response;
|
||||
$response = $shield.$json_response;
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
|
|
@ -29,10 +29,8 @@ final class AphrontJSONResponse extends AphrontResponse {
|
|||
}
|
||||
|
||||
public function buildResponseString() {
|
||||
$response = $this->encodeJSONForHTTPResponse(
|
||||
$this->content,
|
||||
$use_javelin_shield = false);
|
||||
return $response;
|
||||
$response = $this->encodeJSONForHTTPResponse($this->content);
|
||||
return $this->addJSONShield($response, $use_javelin_shield = false);
|
||||
}
|
||||
|
||||
public function getHeaders() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -20,13 +20,13 @@ class PhabricatorAuditActionConstants {
|
|||
|
||||
const CONCERN = 'concern';
|
||||
const ACCEPT = 'accept';
|
||||
// TODO: enable comment
|
||||
//const COMMENT = 'comment';
|
||||
const COMMENT = 'comment';
|
||||
|
||||
public static function getActionNameMap() {
|
||||
static $map = array(
|
||||
self::CONCERN => 'Have Concern',
|
||||
self::ACCEPT => 'Accept',
|
||||
self::COMMENT => 'Comment',
|
||||
self::CONCERN => 'Raise Concern',
|
||||
self::ACCEPT => 'Accept Commit',
|
||||
);
|
||||
|
||||
return $map;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,7 +16,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class PhabricatorAuditStatusConstants {
|
||||
final class PhabricatorAuditStatusConstants {
|
||||
|
||||
const NONE = '';
|
||||
const AUDIT_NOT_REQUIRED = 'audit-not-required';
|
||||
|
@ -26,14 +26,18 @@ class PhabricatorAuditStatusConstants {
|
|||
|
||||
public static function getStatusNameMap() {
|
||||
static $map = array(
|
||||
self::NONE => 'Not Apply',
|
||||
self::AUDIT_NOT_REQUIRED => 'Audit Not Required',
|
||||
self::AUDIT_REQUIRED => 'Audit Required',
|
||||
self::CONCERNED => 'Concerned',
|
||||
self::ACCEPTED => 'Accepted',
|
||||
self::NONE => 'Not Applicable',
|
||||
self::AUDIT_NOT_REQUIRED => 'Audit Not Required',
|
||||
self::AUDIT_REQUIRED => 'Audit Required',
|
||||
self::CONCERNED => 'Concern Raised',
|
||||
self::ACCEPTED => 'Accepted',
|
||||
);
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
public static function getStatusName($code) {
|
||||
return idx(self::getStatusNameMap(), $code, 'Unknown');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,5 +6,7 @@
|
|||
|
||||
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorAuditStatusConstants.php');
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorAuditAddCommentController
|
||||
extends PhabricatorAuditController {
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
if (!$request->isFormPost()) {
|
||||
return new Aphront403Response();
|
||||
}
|
||||
|
||||
$commit_phid = $request->getStr('commit');
|
||||
$commit = id(new PhabricatorRepositoryCommit())->loadOneWhere(
|
||||
'phid = %s',
|
||||
$commit_phid);
|
||||
|
||||
if (!$commit) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$comment = id(new PhabricatorAuditComment())
|
||||
->setAction($request->getStr('action'))
|
||||
->setContent($request->getStr('content'));
|
||||
|
||||
id(new PhabricatorAuditCommentEditor($commit))
|
||||
->setUser($user)
|
||||
->addComment($comment);
|
||||
|
||||
$phids = array($commit_phid);
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
|
||||
$uri = $handles[$commit_phid]->getURI();
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($uri);
|
||||
}
|
||||
|
||||
}
|
21
src/applications/audit/controller/addcomment/__init__.php
Normal file
21
src/applications/audit/controller/addcomment/__init__.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/response/403');
|
||||
phutil_require_module('phabricator', 'aphront/response/404');
|
||||
phutil_require_module('phabricator', 'aphront/response/redirect');
|
||||
phutil_require_module('phabricator', 'applications/audit/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/audit/editor/comment');
|
||||
phutil_require_module('phabricator', 'applications/audit/storage/auditcomment');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'applications/repository/storage/commit');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorAuditAddCommentController.php');
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -228,53 +228,21 @@ class PhabricatorAuditEditController extends PhabricatorAuditController {
|
|||
|
||||
private function saveAuditComments() {
|
||||
$action = $this->request->getStr('action');
|
||||
$status_map = PhabricatorAuditActionConstants::getStatusNameMap();
|
||||
$status = idx($status_map, $action, null);
|
||||
if ($status === null) {
|
||||
return $this->buildStandardPageResponse(
|
||||
id(new AphrontErrorView())
|
||||
->setSeverity(AphrontErrorView::SEVERITY_ERROR)
|
||||
->setTitle("Action {$action} is invalid."),
|
||||
array(
|
||||
'title' => 'Audit a Commit',
|
||||
));
|
||||
|
||||
$commit = id(new PhabricatorRepositoryCommit())->loadOneWhere(
|
||||
'phid = %s',
|
||||
$this->commitPHID);
|
||||
if (!$commit) {
|
||||
throw new Exception("No such commit!");
|
||||
}
|
||||
|
||||
id(new PhabricatorAuditComment())
|
||||
->setActorPHID($this->user->getPHID())
|
||||
->setTargetPHID($this->commitPHID)
|
||||
$comment = id(new PhabricatorAuditComment())
|
||||
->setAction($action)
|
||||
->setContent($this->request->getStr('comments'))
|
||||
->save();
|
||||
->setContent($this->request->getStr('comments'));
|
||||
|
||||
// Update the audit status for all the relationships <commit, package>
|
||||
// where the package is owned by the user. When a user owns several
|
||||
// packages and a commit touches all of them,It should be good enough for
|
||||
// the user to approve it once to get all the relationships automatically
|
||||
// updated.
|
||||
$owned_packages = id(new PhabricatorOwnersOwner())->loadAllWhere(
|
||||
'userPHID = %s',
|
||||
$this->user->getPHID());
|
||||
$owned_package_ids = mpull($owned_packages, 'getPackageID');
|
||||
|
||||
$conn_r = id(new PhabricatorOwnersPackage())->establishConnection('r');
|
||||
$owned_package_phids = queryfx_all(
|
||||
$conn_r,
|
||||
'SELECT `phid` FROM %T WHERE id IN (%Ld)',
|
||||
id(new PhabricatorOwnersPackage())->getTableName(),
|
||||
$owned_package_ids);
|
||||
$owned_package_phids = ipull($owned_package_phids, 'phid');
|
||||
|
||||
$relationships = id(new PhabricatorOwnersPackageCommitRelationship())
|
||||
->loadAllWhere(
|
||||
'commitPHID = %s AND packagePHID IN (%Ls)',
|
||||
$this->commitPHID,
|
||||
$owned_package_phids);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
$relationship->setAuditStatus($status);
|
||||
$relationship->save();
|
||||
}
|
||||
$editor = id(new PhabricatorAuditCommentEditor($commit))
|
||||
->setUser($this->user)
|
||||
->addComment($comment);
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI(sprintf('/audit/edit/?c-phid=%s&p-phid=%s',
|
||||
|
|
|
@ -11,12 +11,14 @@ phutil_require_module('phabricator', 'aphront/response/redirect');
|
|||
phutil_require_module('phabricator', 'applications/audit/constants/action');
|
||||
phutil_require_module('phabricator', 'applications/audit/constants/status');
|
||||
phutil_require_module('phabricator', 'applications/audit/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/audit/editor/comment');
|
||||
phutil_require_module('phabricator', 'applications/audit/storage/auditcomment');
|
||||
phutil_require_module('phabricator', 'applications/differential/storage/revision');
|
||||
phutil_require_module('phabricator', 'applications/owners/storage/owner');
|
||||
phutil_require_module('phabricator', 'applications/owners/storage/package');
|
||||
phutil_require_module('phabricator', 'applications/owners/storage/packagecommitrelationship');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'applications/repository/storage/commit');
|
||||
phutil_require_module('phabricator', 'storage/queryfx');
|
||||
phutil_require_module('phabricator', 'view/form/base');
|
||||
phutil_require_module('phabricator', 'view/form/control/divider');
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorAuditListController extends PhabricatorAuditController {
|
||||
|
||||
private $filter;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->filter = idx($data, 'filter');
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
|
||||
$nav = new AphrontSideNavFilterView();
|
||||
$nav->setBaseURI(new PhutilURI('/audit/view/'));
|
||||
$nav->addLabel('Audits');
|
||||
$nav->addFilter('all', 'All');
|
||||
|
||||
$this->filter = $nav->selectFilter($this->filter, 'all');
|
||||
|
||||
$pager = new AphrontPagerView();
|
||||
$pager->setURI($request->getRequestURI(), 'offset');
|
||||
|
||||
$query = new PhabricatorAuditQuery();
|
||||
$query->setOffset($pager->getOffset());
|
||||
$query->setLimit($pager->getPageSize() + 1);
|
||||
|
||||
$audits = $query->execute();
|
||||
$audits = $pager->sliceResults($audits);
|
||||
|
||||
$view = new PhabricatorAuditListView();
|
||||
$view->setAudits($audits);
|
||||
|
||||
$phids = $view->getRequiredHandlePHIDs();
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
|
||||
$view->setHandles($handles);
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->appendChild($view);
|
||||
$panel->setHeader('Audits');
|
||||
|
||||
$nav->appendChild($panel);
|
||||
$nav->appendChild($pager);
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
$nav,
|
||||
array(
|
||||
'title' => 'Audits',
|
||||
));
|
||||
}
|
||||
|
||||
}
|
21
src/applications/audit/controller/list/__init__.php
Normal file
21
src/applications/audit/controller/list/__init__.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/audit/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/audit/query/audit');
|
||||
phutil_require_module('phabricator', 'applications/audit/view/list');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'view/control/pager');
|
||||
phutil_require_module('phabricator', 'view/layout/panel');
|
||||
phutil_require_module('phabricator', 'view/layout/sidenavfilter');
|
||||
|
||||
phutil_require_module('phutil', 'parser/uri');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorAuditListController.php');
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorAuditCommentEditor {
|
||||
|
||||
private $commit;
|
||||
private $user;
|
||||
|
||||
public function __construct(PhabricatorRepositoryCommit $commit) {
|
||||
$this->commit = $commit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUser(PhabricatorUser $user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addComment(PhabricatorAuditComment $comment) {
|
||||
|
||||
$commit = $this->commit;
|
||||
$user = $this->user;
|
||||
|
||||
$comment
|
||||
->setActorPHID($user->getPHID())
|
||||
->setTargetPHID($commit->getPHID())
|
||||
->save();
|
||||
|
||||
// When a user submits an audit comment, we update all the audit requests
|
||||
// they have authority over to reflect the most recent status. The general
|
||||
// idea here is that if audit has triggered for, e.g., several packages, but
|
||||
// a user owns all of them, they can clear the audit requirement in one go
|
||||
// without auditing the commit for each trigger.
|
||||
|
||||
$audit_phids = self::loadAuditPHIDsForUser($this->user);
|
||||
$audit_phids = array_fill_keys($audit_phids, true);
|
||||
|
||||
$relationships = id(new PhabricatorOwnersPackageCommitRelationship())
|
||||
->loadAllWhere(
|
||||
'commitPHID = %s',
|
||||
$commit->getPHID());
|
||||
|
||||
$action = $comment->getAction();
|
||||
$status_map = PhabricatorAuditActionConstants::getStatusNameMap();
|
||||
$status = idx($status_map, $action, null);
|
||||
|
||||
// Status may be empty for updates which don't affect status, like
|
||||
// "comment".
|
||||
if ($status) {
|
||||
foreach ($relationships as $relationship) {
|
||||
if (empty($audit_phids[$relationship->getPackagePHID()])) {
|
||||
continue;
|
||||
}
|
||||
$relationship->setAuditStatus($status);
|
||||
$relationship->save();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: News feed.
|
||||
// TODO: Search index.
|
||||
// TODO: Email.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load the PHIDs for all objects the user has the authority to act as an
|
||||
* audit for. This includes themselves, and any packages they are an owner
|
||||
* of.
|
||||
*/
|
||||
public static function loadAuditPHIDsForUser(PhabricatorUser $user) {
|
||||
$phids = array();
|
||||
|
||||
// The user can audit on their own behalf.
|
||||
$phids[$user->getPHID()] = true;
|
||||
|
||||
// The user can audit on behalf of all packages they own.
|
||||
$owned_packages = id(new PhabricatorOwnersOwner())->loadAllWhere(
|
||||
'userPHID = %s',
|
||||
$user->getPHID());
|
||||
if ($owned_packages) {
|
||||
$packages = id(new PhabricatorOwnersPackage())->loadAllWhere(
|
||||
'id IN (%Ld)',
|
||||
mpull($owned_packages, 'getPackageID'));
|
||||
foreach (mpull($packages, 'getPHID') as $phid) {
|
||||
$phids[$phid] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// The user can audit on behalf of all projects they are a member of.
|
||||
$query = new PhabricatorProjectQuery();
|
||||
$query->setMembers(array($user->getPHID));
|
||||
$projects = $query->execute();
|
||||
foreach ($projects as $project) {
|
||||
$phids[$project->getPHID()] = true;
|
||||
}
|
||||
|
||||
return array_keys($phids);
|
||||
}
|
||||
|
||||
}
|
18
src/applications/audit/editor/comment/__init__.php
Normal file
18
src/applications/audit/editor/comment/__init__.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/audit/constants/action');
|
||||
phutil_require_module('phabricator', 'applications/owners/storage/owner');
|
||||
phutil_require_module('phabricator', 'applications/owners/storage/package');
|
||||
phutil_require_module('phabricator', 'applications/owners/storage/packagecommitrelationship');
|
||||
phutil_require_module('phabricator', 'applications/project/query/project');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorAuditCommentEditor.php');
|
91
src/applications/audit/query/audit/PhabricatorAuditQuery.php
Normal file
91
src/applications/audit/query/audit/PhabricatorAuditQuery.php
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorAuditQuery {
|
||||
|
||||
private $offset;
|
||||
private $limit;
|
||||
|
||||
private $commitPHIDs;
|
||||
|
||||
public function withCommitPHIDs(array $commit_phids) {
|
||||
$this->commitPHIDs = $commit_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setOffset($offset) {
|
||||
$this->offset = $offset;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setLimit($limit) {
|
||||
$this->limit = $limit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function execute() {
|
||||
$table = new PhabricatorOwnersPackageCommitRelationship();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
|
||||
$where = $this->buildWhereClause($conn_r);
|
||||
$limit = $this->buildLimitClause($conn_r);
|
||||
|
||||
$data = queryfx_all(
|
||||
$conn_r,
|
||||
'SELECT * FROM %T %Q %Q',
|
||||
$table->getTableName(),
|
||||
$where,
|
||||
$limit);
|
||||
|
||||
$audits = $table->loadAllFromArray($data);
|
||||
return $audits;
|
||||
|
||||
}
|
||||
|
||||
private function buildWhereClause($conn_r) {
|
||||
$where = array();
|
||||
|
||||
if ($this->commitPHIDs) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'commitPHID IN (%Ls)',
|
||||
$this->commitPHIDs);
|
||||
}
|
||||
|
||||
if ($where) {
|
||||
$where = 'WHERE ('.implode(') AND (', $where).')';
|
||||
} else {
|
||||
$where = '';
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
private function buildLimitClause($conn_r) {
|
||||
if ($this->limit && $this->offset) {
|
||||
return qsprintf($conn_r, 'LIMIT %d, %d', $this->offset, $this->limit);
|
||||
} else if ($this->limit) {
|
||||
return qsprintf($conn_r, 'LIMIT %d', $this->limit);
|
||||
} else if ($this->offset) {
|
||||
return qsprintf($conn_r, 'LIMIT %d, %d', $this->offset, PHP_INT_MAX);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
14
src/applications/audit/query/audit/__init__.php
Normal file
14
src/applications/audit/query/audit/__init__.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/owners/storage/packagecommitrelationship');
|
||||
phutil_require_module('phabricator', 'storage/qsprintf');
|
||||
phutil_require_module('phabricator', 'storage/queryfx');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorAuditQuery.php');
|
102
src/applications/audit/view/list/PhabricatorAuditListView.php
Normal file
102
src/applications/audit/view/list/PhabricatorAuditListView.php
Normal file
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorAuditListView extends AphrontView {
|
||||
|
||||
private $audits;
|
||||
private $handles;
|
||||
|
||||
public function setAudits(array $audits) {
|
||||
$this->audits = $audits;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHandles(array $handles) {
|
||||
$this->handles = $handles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRequiredHandlePHIDs() {
|
||||
$phids = array();
|
||||
foreach ($this->audits as $audit) {
|
||||
$phids[$audit->getCommitPHID()] = true;
|
||||
$phids[$audit->getPackagePHID()] = true;
|
||||
}
|
||||
return array_keys($phids);
|
||||
}
|
||||
|
||||
private function getHandle($phid) {
|
||||
$handle = idx($this->handles, $phid);
|
||||
if (!$handle) {
|
||||
throw new Exception("No handle for '{$phid}'!");
|
||||
}
|
||||
return $handle;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
|
||||
$last = null;
|
||||
$rows = array();
|
||||
foreach ($this->audits as $audit) {
|
||||
$commit_phid = $audit->getCommitPHID();
|
||||
if ($last == $commit_phid) {
|
||||
$commit_name = null;
|
||||
} else {
|
||||
$commit_name = $this->getHandle($commit_phid)->renderLink();
|
||||
$last = $commit_phid;
|
||||
}
|
||||
|
||||
$reasons = $audit->getAuditReasons();
|
||||
foreach ($reasons as $key => $reason) {
|
||||
$reasons[$key] = phutil_escape_html($reason);
|
||||
}
|
||||
$reasons = implode('<br />', $reasons);
|
||||
|
||||
$status_code = $audit->getAuditStatus();
|
||||
$status = PhabricatorAuditStatusConstants::getStatusName($status_code);
|
||||
|
||||
$auditor_handle = $this->getHandle($audit->getPackagePHID());
|
||||
$rows[] = array(
|
||||
$commit_name,
|
||||
$auditor_handle->renderLink(),
|
||||
phutil_escape_html($status),
|
||||
$reasons,
|
||||
);
|
||||
}
|
||||
|
||||
$table = new AphrontTableView($rows);
|
||||
$table->setHeaders(
|
||||
array(
|
||||
'Commit',
|
||||
'Auditor',
|
||||
'Status',
|
||||
'Details',
|
||||
));
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
'pri',
|
||||
'',
|
||||
'',
|
||||
'wide',
|
||||
));
|
||||
|
||||
|
||||
return $table->render();
|
||||
}
|
||||
|
||||
}
|
17
src/applications/audit/view/list/__init__.php
Normal file
17
src/applications/audit/view/list/__init__.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/audit/constants/status');
|
||||
phutil_require_module('phabricator', 'view/base');
|
||||
phutil_require_module('phabricator', 'view/control/table');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorAuditListView.php');
|
|
@ -21,6 +21,7 @@ abstract class PhabricatorOAuthProvider {
|
|||
const PROVIDER_FACEBOOK = 'facebook';
|
||||
const PROVIDER_GITHUB = 'github';
|
||||
const PROVIDER_GOOGLE = 'google';
|
||||
const PROVIDER_PHABRICATOR = 'phabricator';
|
||||
|
||||
private $accessToken;
|
||||
|
||||
|
@ -108,6 +109,9 @@ abstract class PhabricatorOAuthProvider {
|
|||
case self::PROVIDER_GOOGLE:
|
||||
$class = 'PhabricatorOAuthProviderGoogle';
|
||||
break;
|
||||
case self::PROVIDER_PHABRICATOR:
|
||||
$class = 'PhabricatorOAuthProviderPhabricator';
|
||||
break;
|
||||
default:
|
||||
throw new Exception('Unknown OAuth provider.');
|
||||
}
|
||||
|
@ -120,6 +124,7 @@ abstract class PhabricatorOAuthProvider {
|
|||
self::PROVIDER_FACEBOOK,
|
||||
self::PROVIDER_GITHUB,
|
||||
self::PROVIDER_GOOGLE,
|
||||
self::PROVIDER_PHABRICATOR,
|
||||
);
|
||||
$providers = array();
|
||||
foreach ($all as $provider) {
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorOAuthProviderPhabricator
|
||||
extends PhabricatorOAuthProvider {
|
||||
|
||||
private $userData;
|
||||
|
||||
public function decodeTokenResponse($response) {
|
||||
$decoded = json_decode($response, true);
|
||||
if (!is_array($decoded)) {
|
||||
throw new Exception('Invalid token response.');
|
||||
}
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
public function getProviderKey() {
|
||||
return self::PROVIDER_PHABRICATOR;
|
||||
}
|
||||
|
||||
public function getProviderName() {
|
||||
return 'Phabricator';
|
||||
}
|
||||
|
||||
public function isProviderEnabled() {
|
||||
return PhabricatorEnv::getEnvConfig('phabricator.auth-enabled');
|
||||
}
|
||||
|
||||
public function isProviderLinkPermanent() {
|
||||
return PhabricatorEnv::getEnvConfig('phabricator.auth-permanent');
|
||||
}
|
||||
|
||||
public function isProviderRegistrationEnabled() {
|
||||
return PhabricatorEnv::getEnvConfig('phabricator.registration-enabled');
|
||||
}
|
||||
|
||||
public function getClientID() {
|
||||
return PhabricatorEnv::getEnvConfig('phabricator.application-id');
|
||||
}
|
||||
|
||||
public function renderGetClientIDHelp() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getClientSecret() {
|
||||
return PhabricatorEnv::getEnvConfig('phabricator.application-secret');
|
||||
}
|
||||
|
||||
public function renderGetClientSecretHelp() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getAuthURI() {
|
||||
return $this->getURI('/oauthserver/auth/');
|
||||
}
|
||||
|
||||
public function getTestURIs() {
|
||||
return array(
|
||||
$this->getURI('/'),
|
||||
$this->getURI('/api/user.whoami/')
|
||||
);
|
||||
}
|
||||
|
||||
public function getTokenURI() {
|
||||
return $this->getURI('/oauthserver/token/');
|
||||
}
|
||||
|
||||
public function getUserInfoURI() {
|
||||
return $this->getURI('/api/user.whoami');
|
||||
}
|
||||
|
||||
public function getMinimumScope() {
|
||||
return 'email';
|
||||
}
|
||||
|
||||
public function setUserData($data) {
|
||||
// need to strip the javascript shield from conduit
|
||||
$data = substr($data, 8);
|
||||
$data = json_decode($data, true);
|
||||
if (!is_array($data)) {
|
||||
throw new Exception('Invalid user data.');
|
||||
}
|
||||
$this->userData = $data['result'];
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function retrieveUserID() {
|
||||
return $this->userData['phid'];
|
||||
}
|
||||
|
||||
public function retrieveUserEmail() {
|
||||
return $this->userData['email'];
|
||||
}
|
||||
|
||||
public function retrieveUserAccountName() {
|
||||
return $this->userData['userName'];
|
||||
}
|
||||
|
||||
public function retrieveUserProfileImage() {
|
||||
$uri = $this->userData['image'];
|
||||
return @file_get_contents($uri);
|
||||
}
|
||||
|
||||
public function retrieveUserAccountURI() {
|
||||
return $this->userData['uri'];
|
||||
}
|
||||
|
||||
public function retrieveUserRealName() {
|
||||
return $this->userData['realName'];
|
||||
}
|
||||
|
||||
private function getURI($path) {
|
||||
return
|
||||
rtrim(PhabricatorEnv::getEnvConfig('phabricator.oauth-uri'), '/') .
|
||||
$path;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/auth/oauth/provider/base');
|
||||
phutil_require_module('phabricator', 'infrastructure/env');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorOAuthProviderPhabricator.php');
|
|
@ -114,6 +114,7 @@ class PhabricatorConduitAPIController
|
|||
$allow_unguarded_writes = false;
|
||||
$auth_error = null;
|
||||
if ($method_handler->shouldRequireAuthentication()) {
|
||||
$metadata['scope'] = $method_handler->getRequiredScope();
|
||||
$auth_error = $this->authenticateUser($api_request, $metadata);
|
||||
// If we've explicitly authenticated the user here and either done
|
||||
// CSRF validation or are using a non-web authentication mechanism.
|
||||
|
@ -247,6 +248,48 @@ class PhabricatorConduitAPIController
|
|||
return null;
|
||||
}
|
||||
|
||||
// handle oauth
|
||||
// TODO - T897 (make error codes for OAuth more correct to spec)
|
||||
// and T891 (strip shield from Conduit response)
|
||||
$access_token = $request->getStr('access_token');
|
||||
$method_scope = $metadata['scope'];
|
||||
if ($access_token &&
|
||||
$method_scope != PhabricatorOAuthServerScope::SCOPE_NOT_ACCESSIBLE) {
|
||||
$token = id(new PhabricatorOAuthServerAccessToken())
|
||||
->loadOneWhere('token = %s',
|
||||
$access_token);
|
||||
if (!$token) {
|
||||
return array(
|
||||
'ERR-INVALID-AUTH',
|
||||
'Access token does not exist.',
|
||||
);
|
||||
}
|
||||
|
||||
$oauth_server = new PhabricatorOAuthServer();
|
||||
$valid = $oauth_server->validateAccessToken($token,
|
||||
$method_scope);
|
||||
if (!$valid) {
|
||||
return array(
|
||||
'ERR-INVALID-AUTH',
|
||||
'Access token is invalid.',
|
||||
);
|
||||
}
|
||||
|
||||
// valid token, so let's log in the user!
|
||||
$user_phid = $token->getUserPHID();
|
||||
$user = id(new PhabricatorUser())
|
||||
->loadOneWhere('phid = %s',
|
||||
$user_phid);
|
||||
if (!$user) {
|
||||
return array(
|
||||
'ERR-INVALID-AUTH',
|
||||
'Access token is for invalid user.',
|
||||
);
|
||||
}
|
||||
$api_request->setUser($user);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Handle sessionless auth. TOOD: This is super messy.
|
||||
if (isset($metadata['authUser'])) {
|
||||
$user = id(new PhabricatorUser())->loadOneWhere(
|
||||
|
|
|
@ -13,6 +13,9 @@ phutil_require_module('phabricator', 'applications/conduit/method/base');
|
|||
phutil_require_module('phabricator', 'applications/conduit/protocol/request');
|
||||
phutil_require_module('phabricator', 'applications/conduit/protocol/response');
|
||||
phutil_require_module('phabricator', 'applications/conduit/storage/methodcalllog');
|
||||
phutil_require_module('phabricator', 'applications/oauthserver/scope');
|
||||
phutil_require_module('phabricator', 'applications/oauthserver/server');
|
||||
phutil_require_module('phabricator', 'applications/oauthserver/storage/accesstoken');
|
||||
phutil_require_module('phabricator', 'applications/people/storage/user');
|
||||
phutil_require_module('phabricator', 'storage/queryfx');
|
||||
phutil_require_module('phabricator', 'view/control/table');
|
||||
|
|
|
@ -35,6 +35,11 @@ abstract class ConduitAPIMethod {
|
|||
return idx($this->defineErrorTypes(), $error_code, 'Unknown Error');
|
||||
}
|
||||
|
||||
public function getRequiredScope() {
|
||||
// by default, conduit methods are not accessible via OAuth
|
||||
return PhabricatorOAuthServerScope::SCOPE_NOT_ACCESSIBLE;
|
||||
}
|
||||
|
||||
public function executeMethod(ConduitAPIRequest $request) {
|
||||
return $this->execute($request);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/oauthserver/scope');
|
||||
phutil_require_module('phabricator', 'infrastructure/env');
|
||||
|
||||
phutil_require_module('phutil', 'parser/uri');
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -22,10 +22,21 @@
|
|||
abstract class ConduitAPI_user_Method extends ConduitAPIMethod {
|
||||
|
||||
protected function buildUserInformationDictionary(PhabricatorUser $user) {
|
||||
$src_phid = $user->getProfileImagePHID();
|
||||
$file = id(new PhabricatorFile())->loadOneWhere('phid = %s', $src_phid);
|
||||
if ($file) {
|
||||
$picture = $file->getBestURI();
|
||||
} else {
|
||||
$picture = null;
|
||||
}
|
||||
|
||||
return array(
|
||||
'phid' => $user->getPHID(),
|
||||
'userName' => $user->getUserName(),
|
||||
'realName' => $user->getRealName(),
|
||||
'email' => $user->getEmail(),
|
||||
'image' => $picture,
|
||||
'uri' => PhabricatorEnv::getURI('/p/'.$user->getUsername().'/'),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/conduit/method/base');
|
||||
phutil_require_module('phabricator', 'applications/files/storage/file');
|
||||
phutil_require_module('phabricator', 'infrastructure/env');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('ConduitAPI_user_Method.php');
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -40,6 +40,10 @@ final class ConduitAPI_user_whoami_Method
|
|||
);
|
||||
}
|
||||
|
||||
public function getRequiredScope() {
|
||||
return PhabricatorOAuthServerScope::SCOPE_WHOAMI;
|
||||
}
|
||||
|
||||
protected function execute(ConduitAPIRequest $request) {
|
||||
return $this->buildUserInformationDictionary($request->getUser());
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/conduit/method/user/base');
|
||||
phutil_require_module('phabricator', 'applications/oauthserver/scope');
|
||||
|
||||
|
||||
phutil_require_source('ConduitAPI_user_whoami_Method.php');
|
||||
|
|
|
@ -366,6 +366,10 @@ class DifferentialRevisionListController extends DifferentialController {
|
|||
private function buildViews($filter, $user_phid, array $revisions) {
|
||||
$user = $this->getRequest()->getUser();
|
||||
|
||||
$template = id(new DifferentialRevisionListView())
|
||||
->setUser($user)
|
||||
->setFields(DifferentialRevisionListView::getDefaultFields());
|
||||
|
||||
$views = array();
|
||||
switch ($filter) {
|
||||
case 'active':
|
||||
|
@ -373,18 +377,16 @@ class DifferentialRevisionListController extends DifferentialController {
|
|||
$revisions,
|
||||
$user_phid);
|
||||
|
||||
$view = id(new DifferentialRevisionListView())
|
||||
$view = id(clone $template)
|
||||
->setRevisions($active)
|
||||
->setUser($user)
|
||||
->setNoDataString("You have no active revisions requiring action.");
|
||||
$views[] = array(
|
||||
'title' => 'Action Required',
|
||||
'view' => $view,
|
||||
);
|
||||
|
||||
$view = id(new DifferentialRevisionListView())
|
||||
$view = id(clone $template)
|
||||
->setRevisions($waiting)
|
||||
->setUser($user)
|
||||
->setNoDataString("You have no active revisions waiting on others.");
|
||||
$views[] = array(
|
||||
'title' => 'Waiting On Others',
|
||||
|
@ -401,9 +403,8 @@ class DifferentialRevisionListController extends DifferentialController {
|
|||
'subscribed' => 'Revisions by Subscriber',
|
||||
'all' => 'Revisions',
|
||||
);
|
||||
$view = id(new DifferentialRevisionListView())
|
||||
->setRevisions($revisions)
|
||||
->setUser($user);
|
||||
$view = id(clone $template)
|
||||
->setRevisions($revisions);
|
||||
$views[] = array(
|
||||
'title' => idx($titles, $filter),
|
||||
'view' => $view,
|
||||
|
@ -412,6 +413,7 @@ class DifferentialRevisionListController extends DifferentialController {
|
|||
default:
|
||||
throw new Exception("Unknown filter '{$filter}'!");
|
||||
}
|
||||
|
||||
return $views;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class DifferentialRevisionStatsController extends DifferentialController {
|
||||
private $filter;
|
||||
|
||||
public function shouldRequireLogin() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private function loadRevisions($phid) {
|
||||
$table = new DifferentialRevision();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
$rows = queryfx_all(
|
||||
$conn_r,
|
||||
'SELECT revisions.* FROM %T revisions ' .
|
||||
'JOIN %T comments ON comments.revisionID = revisions.id ' .
|
||||
'JOIN (' .
|
||||
' SELECT revisionID FROM %T WHERE objectPHID = %s ' .
|
||||
' UNION ALL ' .
|
||||
' SELECT id from differential_revision WHERE authorPHID = %s) rel ' .
|
||||
'ON (comments.revisionID = rel.revisionID)' .
|
||||
'WHERE comments.action = %s' .
|
||||
'AND comments.authorPHID = %s',
|
||||
$table->getTableName(),
|
||||
id(new DifferentialComment())->getTableName(),
|
||||
DifferentialRevision::RELATIONSHIP_TABLE,
|
||||
$phid,
|
||||
$phid,
|
||||
$this->filter,
|
||||
$phid
|
||||
);
|
||||
return $table->loadAllFromArray($rows);
|
||||
}
|
||||
|
||||
private function loadComments($phid) {
|
||||
$table = new DifferentialComment();
|
||||
$conn_r = $table->establishConnection('r');
|
||||
$rows = queryfx_all(
|
||||
$conn_r,
|
||||
'SELECT comments.* FROM %T comments ' .
|
||||
'JOIN (' .
|
||||
' SELECT revisionID FROM %T WHERE objectPHID = %s ' .
|
||||
' UNION ALL ' .
|
||||
' SELECT id from differential_revision WHERE authorPHID = %s) rel ' .
|
||||
'ON (comments.revisionID = rel.revisionID)' .
|
||||
'WHERE comments.action = %s' .
|
||||
'AND comments.authorPHID = %s',
|
||||
$table->getTableName(),
|
||||
DifferentialRevision::RELATIONSHIP_TABLE,
|
||||
$phid,
|
||||
$phid,
|
||||
$this->filter,
|
||||
$phid
|
||||
);
|
||||
|
||||
return $table->loadAllFromArray($rows);
|
||||
}
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->filter = idx($data, 'filter');
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$phid_arr = $request->getArr('view_user');
|
||||
$view_target = head($phid_arr);
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($request->getRequestURI()->alter('phid', $view_target));
|
||||
}
|
||||
|
||||
$params = array_filter(
|
||||
array(
|
||||
'phid' => $request->getStr('phid'),
|
||||
));
|
||||
|
||||
// Fill in the defaults we'll actually use for calculations if any
|
||||
// parameters are missing.
|
||||
$params += array(
|
||||
'phid' => $user->getPHID(),
|
||||
);
|
||||
|
||||
$side_nav = new AphrontSideNavFilterView();
|
||||
$side_nav->setBaseURI(id(new PhutilURI('/differential/stats/'))
|
||||
->alter('phid', $params['phid']));
|
||||
foreach (array(
|
||||
DifferentialAction::ACTION_COMMIT,
|
||||
DifferentialAction::ACTION_ACCEPT,
|
||||
DifferentialAction::ACTION_REJECT,
|
||||
DifferentialAction::ACTION_UPDATE,
|
||||
DifferentialAction::ACTION_COMMENT,
|
||||
) as $action) {
|
||||
$verb = ucfirst(DifferentialAction::getActionPastTenseVerb($action));
|
||||
$side_nav->addFilter($action, $verb);
|
||||
}
|
||||
$this->filter =
|
||||
$side_nav->selectFilter($this->filter,
|
||||
DifferentialAction::ACTION_COMMIT);
|
||||
|
||||
$panels = array();
|
||||
$handles = id(new PhabricatorObjectHandleData(array($params['phid'])))
|
||||
->loadHandles();
|
||||
|
||||
$filter_form = id(new AphrontFormView())
|
||||
->setAction('/differential/stats/'.$this->filter.'/')
|
||||
->setUser($user);
|
||||
|
||||
$filter_form->appendChild(
|
||||
$this->renderControl($params['phid'], $handles));
|
||||
$filter_form->appendChild(id(new AphrontFormSubmitControl())
|
||||
->setValue('Filter Revisions'));
|
||||
|
||||
$side_nav->appendChild($filter_form);
|
||||
|
||||
$comments = $this->loadComments($params['phid']);
|
||||
$revisions = $this->loadRevisions($params['phid']);
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader('Differential rate analysis');
|
||||
$panel->appendChild(
|
||||
id(new DifferentialRevisionStatsView())
|
||||
->setComments($comments)
|
||||
->setRevisions($revisions)
|
||||
->setUser($user));
|
||||
$panels[] = $panel;
|
||||
|
||||
foreach ($panels as $panel) {
|
||||
$side_nav->appendChild($panel);
|
||||
}
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
$side_nav,
|
||||
array(
|
||||
'title' => 'Differential statistics',
|
||||
));
|
||||
}
|
||||
|
||||
private function renderControl($view_phid, $handles) {
|
||||
$value = array();
|
||||
if ($view_phid) {
|
||||
$value = array(
|
||||
$view_phid => $handles[$view_phid]->getFullName(),
|
||||
);
|
||||
}
|
||||
return id(new AphrontFormTokenizerControl())
|
||||
->setDatasource('/typeahead/common/users/')
|
||||
->setLabel('View User')
|
||||
->setName('view_user')
|
||||
->setValue($value)
|
||||
->setLimit(1);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/response/redirect');
|
||||
phutil_require_module('phabricator', 'applications/differential/constants/action');
|
||||
phutil_require_module('phabricator', 'applications/differential/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/differential/storage/comment');
|
||||
phutil_require_module('phabricator', 'applications/differential/storage/revision');
|
||||
phutil_require_module('phabricator', 'applications/differential/view/revisionstats');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'storage/queryfx');
|
||||
phutil_require_module('phabricator', 'view/form/base');
|
||||
phutil_require_module('phabricator', 'view/form/control/submit');
|
||||
phutil_require_module('phabricator', 'view/form/control/tokenizer');
|
||||
phutil_require_module('phabricator', 'view/layout/panel');
|
||||
phutil_require_module('phabricator', 'view/layout/sidenavfilter');
|
||||
|
||||
phutil_require_module('phutil', 'parser/uri');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DifferentialRevisionStatsController.php');
|
|
@ -663,7 +663,11 @@ class DifferentialRevisionEditor {
|
|||
->setAuthorPHID($this->getActorPHID())
|
||||
->setRevisionID($revision_id)
|
||||
->setContent($this->getComments())
|
||||
->setAction('update');
|
||||
->setAction(DifferentialAction::ACTION_UPDATE)
|
||||
->setMetadata(
|
||||
array(
|
||||
DifferentialComment::METADATA_DIFF_ID => $this->getDiff()->getID(),
|
||||
));
|
||||
|
||||
if ($this->contentSource) {
|
||||
$comment->setContentSource($this->contentSource);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -30,4 +30,8 @@ abstract class DifferentialFieldSelector {
|
|||
|
||||
abstract public function getFieldSpecifications();
|
||||
|
||||
public function sortFieldsForRevisionList(array $fields) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -53,9 +53,33 @@ final class DifferentialDefaultFieldSelector
|
|||
new DifferentialApplyPatchFieldSpecification(),
|
||||
new DifferentialRevisionIDFieldSpecification(),
|
||||
new DifferentialGitSVNIDFieldSpecification(),
|
||||
new DifferentialDateModifiedFieldSpecification(),
|
||||
new DifferentialDateCreatedFieldSpecification(),
|
||||
));
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
public function sortFieldsForRevisionList(array $fields) {
|
||||
$map = array();
|
||||
foreach ($fields as $field) {
|
||||
$map[get_class($field)] = $field;
|
||||
}
|
||||
|
||||
$map = array_select_keys(
|
||||
$map,
|
||||
array(
|
||||
'DifferentialRevisionIDFieldSpecification',
|
||||
'DifferentialTitleFieldSpecification',
|
||||
'DifferentialRevisionStatusFieldSpecification',
|
||||
'DifferentialAuthorFieldSpecification',
|
||||
'DifferentialReviewersFieldSpecification',
|
||||
'DifferentialDateModifiedFieldSpecification',
|
||||
'DifferentialDateCreatedFieldSpecification',
|
||||
)) + $map;
|
||||
|
||||
return array_values($map);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ phutil_require_module('phabricator', 'applications/differential/field/specificat
|
|||
phutil_require_module('phabricator', 'applications/differential/field/specification/branch');
|
||||
phutil_require_module('phabricator', 'applications/differential/field/specification/ccs');
|
||||
phutil_require_module('phabricator', 'applications/differential/field/specification/commits');
|
||||
phutil_require_module('phabricator', 'applications/differential/field/specification/datecreated');
|
||||
phutil_require_module('phabricator', 'applications/differential/field/specification/datemodified');
|
||||
phutil_require_module('phabricator', 'applications/differential/field/specification/dependencies');
|
||||
phutil_require_module('phabricator', 'applications/differential/field/specification/gitsvnid');
|
||||
phutil_require_module('phabricator', 'applications/differential/field/specification/host');
|
||||
|
@ -29,5 +31,7 @@ phutil_require_module('phabricator', 'applications/differential/field/specificat
|
|||
phutil_require_module('phabricator', 'applications/differential/field/specification/unit');
|
||||
phutil_require_module('phabricator', 'infrastructure/env');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DifferentialDefaultFieldSelector.php');
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -43,4 +43,21 @@ final class DifferentialAuthorFieldSpecification
|
|||
return $revision->getAuthorPHID();
|
||||
}
|
||||
|
||||
public function shouldAppearOnRevisionList() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function renderHeaderForRevisionList() {
|
||||
return 'Author';
|
||||
}
|
||||
|
||||
public function renderValueForRevisionList(DifferentialRevision $revision) {
|
||||
return $this->getHandle($revision->getAuthorPHID())->renderLink();
|
||||
}
|
||||
|
||||
public function getRequiredHandlePHIDsForRevisionList(
|
||||
DifferentialRevision $revision) {
|
||||
return array($revision->getAuthorPHID());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
* @task storage Field Storage
|
||||
* @task edit Extending the Revision Edit Interface
|
||||
* @task view Extending the Revision View Interface
|
||||
* @task list Extending the Revision List Interface
|
||||
* @task conduit Extending the Conduit View Interface
|
||||
* @task commit Extending Commit Messages
|
||||
* @task load Loading Additional Data
|
||||
|
@ -264,6 +265,59 @@ abstract class DifferentialFieldSpecification {
|
|||
}
|
||||
|
||||
|
||||
/* -( Extending the Revision List Interface )------------------------------ */
|
||||
|
||||
|
||||
/**
|
||||
* Determine if this field should appear in the table on the revision list
|
||||
* interface.
|
||||
*
|
||||
* @return bool True if this field should appear in the table.
|
||||
*
|
||||
* @task list
|
||||
*/
|
||||
public function shouldAppearOnRevisionList() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a column header for revision list tables.
|
||||
*
|
||||
* @return string Column header.
|
||||
*
|
||||
* @task list
|
||||
*/
|
||||
public function renderHeaderForRevisionList() {
|
||||
throw new DifferentialFieldSpecificationIncompleteException($this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Optionally, return a column class for revision list tables.
|
||||
*
|
||||
* @return string CSS class for table cells.
|
||||
*
|
||||
* @task list
|
||||
*/
|
||||
public function getColumnClassForRevisionList() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a table cell value for revision list tables.
|
||||
*
|
||||
* @param DifferentialRevision The revision to render a value for.
|
||||
* @return string Table cell value.
|
||||
*
|
||||
* @task list
|
||||
*/
|
||||
public function renderValueForRevisionList(DifferentialRevision $revision) {
|
||||
throw new DifferentialFieldSpecificationIncompleteException($this);
|
||||
}
|
||||
|
||||
|
||||
/* -( Extending the Conduit Interface )------------------------------------ */
|
||||
|
||||
|
||||
|
@ -483,6 +537,7 @@ abstract class DifferentialFieldSpecification {
|
|||
return array();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify which @{class:PhabricatorObjectHandles} need to be loaded for your
|
||||
* field to render correctly on the view interface.
|
||||
|
@ -498,6 +553,25 @@ abstract class DifferentialFieldSpecification {
|
|||
return $this->getRequiredHandlePHIDs();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify which @{class:PhabricatorObjectHandles} need to be loaded for your
|
||||
* field to render correctly on the list interface.
|
||||
*
|
||||
* This is a more specific version of @{method:getRequiredHandlePHIDs} which
|
||||
* can be overridden to improve field performance by loading only data you
|
||||
* need.
|
||||
*
|
||||
* @param DifferentialRevision The revision to pull PHIDs for.
|
||||
* @return list List of PHIDs to load handles for.
|
||||
* @task load
|
||||
*/
|
||||
public function getRequiredHandlePHIDsForRevisionList(
|
||||
DifferentialRevision $revision) {
|
||||
return array();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify which @{class:PhabricatorObjectHandles} need to be loaded for your
|
||||
* field to render correctly on the edit interface.
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class DifferentialDateCreatedFieldSpecification
|
||||
extends DifferentialFieldSpecification {
|
||||
|
||||
public function shouldAppearOnRevisionList() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function renderHeaderForRevisionList() {
|
||||
return 'Created';
|
||||
}
|
||||
|
||||
public function getColumnClassForRevisionList() {
|
||||
return 'right';
|
||||
}
|
||||
|
||||
public function renderValueForRevisionList(DifferentialRevision $revision) {
|
||||
return phabricator_date($revision->getDateCreated(), $this->getUser());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/differential/field/specification/base');
|
||||
phutil_require_module('phabricator', 'view/utils');
|
||||
|
||||
|
||||
phutil_require_source('DifferentialDateCreatedFieldSpecification.php');
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class DifferentialDateModifiedFieldSpecification
|
||||
extends DifferentialFieldSpecification {
|
||||
|
||||
public function shouldAppearOnRevisionList() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function renderHeaderForRevisionList() {
|
||||
return 'Updated';
|
||||
}
|
||||
|
||||
public function getColumnClassForRevisionList() {
|
||||
return 'right';
|
||||
}
|
||||
|
||||
public function renderValueForRevisionList(DifferentialRevision $revision) {
|
||||
return phabricator_datetime($revision->getDateModified(), $this->getUser());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/differential/field/specification/base');
|
||||
phutil_require_module('phabricator', 'view/utils');
|
||||
|
||||
|
||||
phutil_require_source('DifferentialDateModifiedFieldSpecification.php');
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -32,4 +32,20 @@ final class DifferentialLinesFieldSpecification
|
|||
return phutil_escape_html(number_format($diff->getLineCount()));
|
||||
}
|
||||
|
||||
public function shouldAppearOnRevisionList() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function renderHeaderForRevisionList() {
|
||||
return 'Lines';
|
||||
}
|
||||
|
||||
public function getColumnClassForRevisionList() {
|
||||
return 'n';
|
||||
}
|
||||
|
||||
public function renderValueForRevisionList(DifferentialRevision $revision) {
|
||||
return number_format($revision->getLineCount());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -140,4 +140,36 @@ final class DifferentialReviewersFieldSpecification
|
|||
return $this->parseCommitMessageUserList($value);
|
||||
}
|
||||
|
||||
public function shouldAppearOnRevisionList() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function renderHeaderForRevisionList() {
|
||||
return 'Reviewers';
|
||||
}
|
||||
|
||||
public function renderValueForRevisionList(DifferentialRevision $revision) {
|
||||
$reviewer_phids = $revision->getReviewers();
|
||||
if ($reviewer_phids) {
|
||||
$first = reset($reviewer_phids);
|
||||
if (count($reviewer_phids) > 1) {
|
||||
$suffix = ' (+'.(count($reviewer_phids) - 1).')';
|
||||
} else {
|
||||
$suffix = null;
|
||||
}
|
||||
return $this->getHandle($first)->renderLink().$suffix;
|
||||
} else {
|
||||
return '<em>None</em>';
|
||||
}
|
||||
}
|
||||
|
||||
public function getRequiredHandlePHIDsForRevisionList(
|
||||
DifferentialRevision $revision) {
|
||||
$reviewer_phids = $revision->getReviewers();
|
||||
if ($reviewer_phids) {
|
||||
return array(reset($reviewer_phids));
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -92,4 +92,16 @@ final class DifferentialRevisionIDFieldSpecification
|
|||
return null;
|
||||
}
|
||||
|
||||
public function shouldAppearOnRevisionList() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function renderHeaderForRevisionList() {
|
||||
return 'ID';
|
||||
}
|
||||
|
||||
public function renderValueForRevisionList(DifferentialRevision $revision) {
|
||||
return 'D'.$revision->getID();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -54,4 +54,17 @@ final class DifferentialRevisionStatusFieldSpecification
|
|||
return '<strong>'.$status.'</strong>'.$next_step;
|
||||
}
|
||||
|
||||
public function shouldAppearOnRevisionList() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function renderHeaderForRevisionList() {
|
||||
return 'Status';
|
||||
}
|
||||
|
||||
public function renderValueForRevisionList(DifferentialRevision $revision) {
|
||||
return ArcanistDifferentialRevisionStatus::getNameForRevisionStatus(
|
||||
$revision->getStatus());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -86,4 +86,25 @@ final class DifferentialTitleFieldSpecification
|
|||
return preg_replace('/\s*\n\s*/', ' ', $value);
|
||||
}
|
||||
|
||||
public function shouldAppearOnRevisionList() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function renderHeaderForRevisionList() {
|
||||
return 'Revision';
|
||||
}
|
||||
|
||||
public function getColumnClassForRevisionList() {
|
||||
return 'wide pri';
|
||||
}
|
||||
|
||||
public function renderValueForRevisionList(DifferentialRevision $revision) {
|
||||
return phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/D'.$revision->getID(),
|
||||
),
|
||||
phutil_escape_html($revision->getTitle()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ phutil_require_module('phabricator', 'applications/differential/field/exception/
|
|||
phutil_require_module('phabricator', 'applications/differential/field/specification/base');
|
||||
phutil_require_module('phabricator', 'view/form/control/textarea');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -103,6 +103,11 @@ abstract class DifferentialMail {
|
|||
$template->setIsBulk(true);
|
||||
$template->setRelatedPHID($this->getRevision()->getPHID());
|
||||
|
||||
$mailtags = $this->getMailTags();
|
||||
if ($mailtags) {
|
||||
$template->setMailTags($mailtags);
|
||||
}
|
||||
|
||||
$phids = array();
|
||||
foreach ($to_phids as $phid) {
|
||||
$phids[$phid] = true;
|
||||
|
@ -134,6 +139,10 @@ abstract class DifferentialMail {
|
|||
}
|
||||
}
|
||||
|
||||
protected function getMailTags() {
|
||||
return array();
|
||||
}
|
||||
|
||||
protected function getSubjectPrefix() {
|
||||
return PhabricatorEnv::getEnvConfig('metamta.differential.subject-prefix');
|
||||
}
|
||||
|
|
|
@ -44,6 +44,35 @@ class DifferentialCommentMail extends DifferentialMail {
|
|||
|
||||
}
|
||||
|
||||
protected function getMailTags() {
|
||||
$comment = $this->getComment();
|
||||
$action = $comment->getAction();
|
||||
|
||||
$tags = array();
|
||||
switch ($action) {
|
||||
case DifferentialAction::ACTION_ADDCCS:
|
||||
$tags[] = MetaMTANotificationType::TYPE_DIFFERENTIAL_CC;
|
||||
break;
|
||||
case DifferentialAction::ACTION_COMMIT:
|
||||
$tags[] = MetaMTANotificationType::TYPE_DIFFERENTIAL_COMMITTED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strlen(trim($comment->getContent()))) {
|
||||
switch ($action) {
|
||||
case DifferentialAction::ACTION_COMMIT:
|
||||
// Commit comments are auto-generated and not especially interesting,
|
||||
// so don't tag them as having a comment.
|
||||
break;
|
||||
default:
|
||||
$tags[] = MetaMTANotificationType::TYPE_DIFFERENTIAL_COMMENT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
protected function renderSubject() {
|
||||
$verb = ucwords($this->getVerb());
|
||||
$revision = $this->getRevision();
|
||||
|
|
|
@ -11,6 +11,7 @@ phutil_require_module('arcanist', 'differential/constants/revisionstatus');
|
|||
phutil_require_module('phabricator', 'applications/differential/constants/action');
|
||||
phutil_require_module('phabricator', 'applications/differential/mail/base');
|
||||
phutil_require_module('phabricator', 'applications/differential/storage/comment');
|
||||
phutil_require_module('phabricator', 'applications/metamta/constants/notificationtype');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'infrastructure/env');
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -20,6 +20,7 @@ class DifferentialComment extends DifferentialDAO {
|
|||
|
||||
const METADATA_ADDED_REVIEWERS = 'added-reviewers';
|
||||
const METADATA_ADDED_CCS = 'added-ccs';
|
||||
const METADATA_DIFF_ID = 'diff-id';
|
||||
|
||||
protected $authorPHID;
|
||||
protected $revisionID;
|
||||
|
|
|
@ -96,6 +96,10 @@ class DifferentialChangesetDetailView extends AphrontView {
|
|||
}
|
||||
|
||||
$display_filename = $changeset->getDisplayFilename();
|
||||
|
||||
$buoyant_begin = $this->renderBuoyant($display_filename);
|
||||
$buoyant_end = $this->renderBuoyant(null);
|
||||
|
||||
$output = javelin_render_tag(
|
||||
'div',
|
||||
array(
|
||||
|
@ -109,6 +113,7 @@ class DifferentialChangesetDetailView extends AphrontView {
|
|||
'class' => $class,
|
||||
'id' => $id,
|
||||
),
|
||||
$buoyant_begin.
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
|
@ -118,9 +123,29 @@ class DifferentialChangesetDetailView extends AphrontView {
|
|||
$buttons.
|
||||
'<h1>'.phutil_escape_html($display_filename).'</h1>'.
|
||||
'<div style="clear: both;"></div>'.
|
||||
$this->renderChildren());
|
||||
$this->renderChildren().
|
||||
$buoyant_end);
|
||||
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function renderBuoyant($text) {
|
||||
return javelin_render_tag(
|
||||
'div',
|
||||
array(
|
||||
'sigil' => 'buoyant',
|
||||
'meta' => array(
|
||||
'text' => $text,
|
||||
),
|
||||
'style' => ($text === null)
|
||||
// Current CSS spacing rules cause the "end" anchor to appear too
|
||||
// late in the display document. Shift it up a bit so we drop the
|
||||
// buoyant header sooner. This reduces confusion when using keystroke
|
||||
// navigation.
|
||||
? 'bottom: 60px; position: absolute;'
|
||||
: null,
|
||||
),
|
||||
'');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ class DifferentialChangesetListView extends AphrontView {
|
|||
private $symbolIndexes = array();
|
||||
private $repository;
|
||||
private $diff;
|
||||
private $vsMap;
|
||||
private $vsMap = array();
|
||||
|
||||
public function setChangesets($changesets) {
|
||||
$this->changesets = $changesets;
|
||||
|
@ -106,6 +106,8 @@ class DifferentialChangesetListView extends AphrontView {
|
|||
array());
|
||||
}
|
||||
|
||||
Javelin::initBehavior('buoyant', array());
|
||||
|
||||
$output = array();
|
||||
$mapping = array();
|
||||
$repository = $this->repository;
|
||||
|
|
|
@ -218,8 +218,10 @@ final class DifferentialInlineCommentView extends AphrontView {
|
|||
'<span class="differential-inline-comment-line">'.$line.'</span>'.
|
||||
phutil_escape_html($author).
|
||||
'</div>'.
|
||||
'<div class="phabricator-remarkup">'.
|
||||
$content.
|
||||
'<div class="differential-inline-comment-content">'.
|
||||
'<div class="phabricator-remarkup">'.
|
||||
$content.
|
||||
'</div>'.
|
||||
'</div>');
|
||||
|
||||
return $this->scaffoldMarkup($markup);
|
||||
|
|
|
@ -95,46 +95,9 @@ final class DifferentialRevisionCommentView extends AphrontView {
|
|||
|
||||
$action_class = 'differential-comment-action-'.$action;
|
||||
|
||||
if ($this->preview) {
|
||||
$date = 'COMMENT PREVIEW';
|
||||
} else {
|
||||
$date = phabricator_datetime($comment->getDateCreated(), $this->user);
|
||||
}
|
||||
|
||||
$info = array();
|
||||
|
||||
$content_source = new PhabricatorContentSourceView();
|
||||
$content_source->setContentSource($comment->getContentSource());
|
||||
$content_source->setUser($this->user);
|
||||
$info[] = $content_source->render();
|
||||
|
||||
$info[] = $date;
|
||||
|
||||
$comment_anchor = null;
|
||||
$anchor_name = $this->anchorName;
|
||||
if ($anchor_name != '' && !$this->preview) {
|
||||
Javelin::initBehavior('phabricator-watch-anchor');
|
||||
$info[] = phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'name' => $anchor_name,
|
||||
'id' => $anchor_name,
|
||||
'href' => '#'.$anchor_name,
|
||||
),
|
||||
'D'.$comment->getRevisionID().'#'.$anchor_name);
|
||||
$comment_anchor = 'anchor-'.$anchor_name;
|
||||
}
|
||||
|
||||
$info = implode(' · ', array_filter($info));
|
||||
|
||||
$author = $this->handles[$comment->getAuthorPHID()];
|
||||
$author_link = $author->renderLink();
|
||||
|
||||
$verb = DifferentialAction::getActionPastTenseVerb($comment->getAction());
|
||||
$verb = phutil_escape_html($verb);
|
||||
|
||||
$content = $comment->getContent();
|
||||
$head_content = null;
|
||||
$hide_comments = true;
|
||||
if (strlen(rtrim($content))) {
|
||||
$hide_comments = false;
|
||||
|
@ -157,8 +120,6 @@ final class DifferentialRevisionCommentView extends AphrontView {
|
|||
'</div>';
|
||||
}
|
||||
|
||||
$title = "{$author_link} {$verb} this revision.";
|
||||
|
||||
if ($this->inlines) {
|
||||
$hide_comments = false;
|
||||
$inline_render = array();
|
||||
|
@ -282,63 +243,93 @@ final class DifferentialRevisionCommentView extends AphrontView {
|
|||
$inline_render = null;
|
||||
}
|
||||
|
||||
$background = null;
|
||||
$uri = $author->getImageURI();
|
||||
if ($uri) {
|
||||
$background = "background-image: url('{$uri}');";
|
||||
}
|
||||
$author = $this->handles[$comment->getAuthorPHID()];
|
||||
$author_link = $author->renderLink();
|
||||
|
||||
$metadata_blocks = array();
|
||||
$metadata = $comment->getMetadata();
|
||||
$added_reviewers = idx(
|
||||
$metadata,
|
||||
DifferentialComment::METADATA_ADDED_REVIEWERS);
|
||||
if ($added_reviewers) {
|
||||
$reviewers = 'Added reviewers: '.$this->renderHandleList(
|
||||
$added_reviewers);
|
||||
$metadata_blocks[] = $reviewers;
|
||||
}
|
||||
|
||||
$added_ccs = idx(
|
||||
$metadata,
|
||||
DifferentialComment::METADATA_ADDED_CCS);
|
||||
|
||||
$verb = DifferentialAction::getActionPastTenseVerb($comment->getAction());
|
||||
$verb = phutil_escape_html($verb);
|
||||
|
||||
$actions = array();
|
||||
switch ($comment->getAction()) {
|
||||
case DifferentialAction::ACTION_ADDCCS:
|
||||
$actions[] = "{$author_link} added CCs: ".
|
||||
$this->renderHandleList($added_ccs).".";
|
||||
$added_ccs = null;
|
||||
break;
|
||||
case DifferentialAction::ACTION_ADDREVIEWERS:
|
||||
$actions[] = "{$author_link} added reviewers: ".
|
||||
$this->renderHandleList($added_reviewers).".";
|
||||
$added_reviewers = null;
|
||||
break;
|
||||
case DifferentialAction::ACTION_UPDATE:
|
||||
$diff_id = idx($metadata, DifferentialComment::METADATA_DIFF_ID);
|
||||
if ($diff_id) {
|
||||
$diff_link = phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/D'.$comment->getRevisionID().'?id='.$diff_id,
|
||||
),
|
||||
'Diff #'.phutil_escape_html($diff_id));
|
||||
$actions[] = "{$author_link} updated this revision to {$diff_link}.";
|
||||
} else {
|
||||
$actions[] = "{$author_link} {$verb} this revision.";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$actions[] = "{$author_link} {$verb} this revision.";
|
||||
break;
|
||||
}
|
||||
|
||||
if ($added_reviewers) {
|
||||
$actions[] = "{$author_link} added reviewers: ".
|
||||
$this->renderHandleList($added_reviewers).".";
|
||||
}
|
||||
|
||||
if ($added_ccs) {
|
||||
$ccs = 'Added CCs: '.$this->renderHandleList($added_ccs);
|
||||
$metadata_blocks[] = $ccs;
|
||||
$actions[] = "{$author_link} added CCs: ".
|
||||
$this->renderHandleList($added_ccs).".";
|
||||
}
|
||||
|
||||
if ($metadata_blocks) {
|
||||
$hide_comments = false;
|
||||
$metadata_blocks =
|
||||
'<div class="differential-comment-metadata">'.
|
||||
implode("\n", $metadata_blocks).
|
||||
'</div>';
|
||||
foreach ($actions as $key => $action) {
|
||||
$actions[$key] = '<div>'.$action.'</div>';
|
||||
}
|
||||
|
||||
$xaction_view = id(new PhabricatorTransactionView())
|
||||
->setUser($this->user)
|
||||
->setImageURI($author->getImageURI())
|
||||
->setContentSource($comment->getContentSource())
|
||||
->addClass($action_class)
|
||||
->setActions($actions);
|
||||
|
||||
if ($this->preview) {
|
||||
$xaction_view->setIsPreview($this->preview);
|
||||
} else {
|
||||
$metadata_blocks = null;
|
||||
$xaction_view->setEpoch($comment->getDateCreated());
|
||||
if ($this->anchorName) {
|
||||
$anchor_name = $this->anchorName;
|
||||
$anchor_text = 'D'.$comment->getRevisionID().'#'.$anchor_name;
|
||||
|
||||
$xaction_view->setAnchor($anchor_name, $anchor_text);
|
||||
}
|
||||
}
|
||||
|
||||
$hide_comments_class = ($hide_comments ? 'hide' : '');
|
||||
return phutil_render_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => "differential-comment",
|
||||
'id' => $comment_anchor,
|
||||
'style' => $background,
|
||||
),
|
||||
'<div class="differential-comment-detail '.$action_class.'">'.
|
||||
'<div class="differential-comment-header">'.
|
||||
'<span class="differential-comment-info">'.$info.'</span>'.
|
||||
'<span class="differential-comment-title">'.$title.'</span>'.
|
||||
if (!$hide_comments) {
|
||||
$xaction_view->appendChild(
|
||||
'<div class="differential-comment-core">'.
|
||||
$content.
|
||||
'</div>'.
|
||||
'<div class="differential-comment-content '.$hide_comments_class.'">'.
|
||||
$head_content.
|
||||
$metadata_blocks.
|
||||
'<div class="differential-comment-core">'.
|
||||
$content.
|
||||
'</div>'.
|
||||
$inline_render.
|
||||
'</div>'.
|
||||
'</div>');
|
||||
$inline_render);
|
||||
}
|
||||
|
||||
return $xaction_view->render();
|
||||
}
|
||||
|
||||
private function renderHandleList(array $phids) {
|
||||
|
|
|
@ -9,11 +9,9 @@
|
|||
phutil_require_module('phabricator', 'aphront/writeguard');
|
||||
phutil_require_module('phabricator', 'applications/differential/constants/action');
|
||||
phutil_require_module('phabricator', 'applications/differential/storage/comment');
|
||||
phutil_require_module('phabricator', 'applications/metamta/contentsource/view');
|
||||
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
||||
phutil_require_module('phabricator', 'infrastructure/javelin/api');
|
||||
phutil_require_module('phabricator', 'view/base');
|
||||
phutil_require_module('phabricator', 'view/utils');
|
||||
phutil_require_module('phabricator', 'view/layout/transaction');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
|
|
@ -25,6 +25,12 @@ final class DifferentialRevisionListView extends AphrontView {
|
|||
private $handles;
|
||||
private $user;
|
||||
private $noDataString;
|
||||
private $fields;
|
||||
|
||||
public function setFields(array $fields) {
|
||||
$this->fields = $fields;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setRevisions(array $revisions) {
|
||||
$this->revisions = $revisions;
|
||||
|
@ -33,14 +39,12 @@ final class DifferentialRevisionListView extends AphrontView {
|
|||
|
||||
public function getRequiredHandlePHIDs() {
|
||||
$phids = array();
|
||||
foreach ($this->revisions as $revision) {
|
||||
$phids[] = $revision->getAuthorPHID();
|
||||
$reviewers = $revision->getReviewers();
|
||||
if ($reviewers) {
|
||||
$phids[] = head($reviewers);
|
||||
foreach ($this->fields as $field) {
|
||||
foreach ($this->revisions as $revision) {
|
||||
$phids[] = $field->getRequiredHandlePHIDsForRevisionList($revision);
|
||||
}
|
||||
}
|
||||
return $phids;
|
||||
return array_mergev($phids);
|
||||
}
|
||||
|
||||
public function setHandles(array $handles) {
|
||||
|
@ -65,67 +69,30 @@ final class DifferentialRevisionListView extends AphrontView {
|
|||
throw new Exception("Call setUser() before render()!");
|
||||
}
|
||||
|
||||
foreach ($this->fields as $field) {
|
||||
$field->setUser($this->user);
|
||||
$field->setHandles($this->handles);
|
||||
}
|
||||
|
||||
$rows = array();
|
||||
foreach ($this->revisions as $revision) {
|
||||
$status = $revision->getStatus();
|
||||
$status =
|
||||
ArcanistDifferentialRevisionStatus::getNameForRevisionStatus($status);
|
||||
|
||||
$reviewer_phids = $revision->getReviewers();
|
||||
if ($reviewer_phids) {
|
||||
$first = reset($reviewer_phids);
|
||||
if (count($reviewer_phids) > 1) {
|
||||
$suffix = ' (+'.(count($reviewer_phids) - 1).')';
|
||||
} else {
|
||||
$suffix = null;
|
||||
}
|
||||
$reviewers = $this->handles[$first]->renderLink().$suffix;
|
||||
} else {
|
||||
$reviewers = '<em>None</em>';
|
||||
$row = array();
|
||||
foreach ($this->fields as $field) {
|
||||
$row[] = $field->renderValueForRevisionList($revision);
|
||||
}
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
$link = phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/D'.$revision->getID(),
|
||||
),
|
||||
phutil_escape_html($revision->getTitle()));
|
||||
|
||||
$rows[] = array(
|
||||
'D'.$revision->getID(),
|
||||
$link,
|
||||
phutil_escape_html($status),
|
||||
number_format($revision->getLineCount()),
|
||||
$this->handles[$revision->getAuthorPHID()]->renderLink(),
|
||||
$reviewers,
|
||||
phabricator_datetime($revision->getDateModified(), $user),
|
||||
phabricator_date($revision->getDateCreated(), $user),
|
||||
);
|
||||
$headers = array();
|
||||
$classes = array();
|
||||
foreach ($this->fields as $field) {
|
||||
$headers[] = $field->renderHeaderForRevisionList();
|
||||
$classes[] = $field->getColumnClassForRevisionList();
|
||||
}
|
||||
|
||||
$table = new AphrontTableView($rows);
|
||||
$table->setHeaders(
|
||||
array(
|
||||
'ID',
|
||||
'Revision',
|
||||
'Status',
|
||||
'Lines',
|
||||
'Author',
|
||||
'Reviewers',
|
||||
'Modified',
|
||||
'Created',
|
||||
));
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
null,
|
||||
'wide pri',
|
||||
null,
|
||||
'n',
|
||||
null,
|
||||
null,
|
||||
'right',
|
||||
'right',
|
||||
));
|
||||
$table->setHeaders($headers);
|
||||
$table->setColumnClasses($classes);
|
||||
|
||||
if ($this->noDataString) {
|
||||
$table->setNoDataString($this->noDataString);
|
||||
|
@ -134,4 +101,22 @@ final class DifferentialRevisionListView extends AphrontView {
|
|||
return $table->render();
|
||||
}
|
||||
|
||||
public static function getDefaultFields() {
|
||||
$selector = DifferentialFieldSelector::newSelector();
|
||||
$fields = $selector->getFieldSpecifications();
|
||||
foreach ($fields as $key => $field) {
|
||||
if (!$field->shouldAppearOnRevisionList()) {
|
||||
unset($fields[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$fields) {
|
||||
throw new Exception(
|
||||
"Phabricator configuration has no fields that appear on the list ".
|
||||
"interface!");
|
||||
}
|
||||
|
||||
return $selector->sortFieldsForRevisionList($fields);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,13 +6,10 @@
|
|||
|
||||
|
||||
|
||||
phutil_require_module('arcanist', 'differential/constants/revisionstatus');
|
||||
|
||||
phutil_require_module('phabricator', 'applications/differential/field/selector/base');
|
||||
phutil_require_module('phabricator', 'view/base');
|
||||
phutil_require_module('phabricator', 'view/control/table');
|
||||
phutil_require_module('phabricator', 'view/utils');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Render some distracting statistics on revisions
|
||||
*/
|
||||
final class DifferentialRevisionStatsView extends AphrontView {
|
||||
private $comments;
|
||||
private $revisions;
|
||||
private $user;
|
||||
|
||||
public function setRevisions(array $revisions) {
|
||||
$this->revisions = $revisions;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setComments(array $comments) {
|
||||
$this->comments = $comments;
|
||||
return $this;
|
||||
}
|
||||
public function setUser($user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$user = $this->user;
|
||||
if (!$user) {
|
||||
throw new Exception("Call setUser() before render()!");
|
||||
}
|
||||
|
||||
$id_to_revision_map = array();
|
||||
foreach ($this->revisions as $rev) {
|
||||
$id_to_revision_map[$rev->getID()] = $rev;
|
||||
}
|
||||
$revisions_seen = array();
|
||||
|
||||
$dates = array();
|
||||
$counts = array();
|
||||
$lines = array();
|
||||
$boosts = array();
|
||||
$days_with_diffs = array();
|
||||
$count_active = array();
|
||||
$now = time();
|
||||
$row_array = array();
|
||||
|
||||
foreach (array(
|
||||
'1 week', '2 weeks', '3 weeks',
|
||||
'1 month', '2 months', '3 months', '6 months', '9 months',
|
||||
'1 year', '18 months',
|
||||
'2 years', '3 years', '4 years', '5 years',
|
||||
) as $age) {
|
||||
$dates[$age] = strtotime($age . ' ago');
|
||||
$counts[$age] = 0;
|
||||
$lines[$age] = 0;
|
||||
$count_active[$age] = 0;
|
||||
}
|
||||
|
||||
foreach ($this->comments as $comment) {
|
||||
$rev_date = $comment->getDateCreated();
|
||||
|
||||
$day = phabricator_date($rev_date, $user);
|
||||
$old_daycount = idx($days_with_diffs, $day, 0);
|
||||
$days_with_diffs[$day] = $old_daycount + 1;
|
||||
|
||||
$rev_id = $comment->getRevisionID();
|
||||
|
||||
if (idx($revisions_seen, $rev_id)) {
|
||||
continue;
|
||||
}
|
||||
$rev = $id_to_revision_map[$rev_id];
|
||||
$revisions_seen[$rev_id] = true;
|
||||
|
||||
foreach ($dates as $age => $cutoff) {
|
||||
if ($cutoff > $rev_date) {
|
||||
continue;
|
||||
}
|
||||
if ($rev) {
|
||||
$lines[$age] += $rev->getLineCount();
|
||||
}
|
||||
$counts[$age]++;
|
||||
if (!$old_daycount) {
|
||||
$count_active[$age]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$old_count = 0;
|
||||
foreach ($dates as $age => $cutoff) {
|
||||
$weeks = ($now - $cutoff + 0.) / (7 * 60 * 60 * 24);
|
||||
if ($old_count == $counts[$age]) {
|
||||
continue;
|
||||
}
|
||||
$old_count = $counts[$age];
|
||||
|
||||
$row_array[$age] = array(
|
||||
'Revisions per week' => number_format($counts[$age] / $weeks, 2),
|
||||
'Lines per week' => number_format($lines[$age] / $weeks, 1),
|
||||
'Active days per week' =>
|
||||
number_format($count_active[$age] / $weeks, 1),
|
||||
'Revisions' => number_format($counts[$age]),
|
||||
'Lines' => number_format($lines[$age]),
|
||||
'Lines per diff' => number_format($lines[$age] /
|
||||
($counts[$age] + 0.0001)),
|
||||
'Active days' => number_format($count_active[$age]),
|
||||
);
|
||||
}
|
||||
|
||||
$rows = array();
|
||||
$row_names = array_keys(head($row_array));
|
||||
foreach ($row_names as $row_name) {
|
||||
$rows[] = array($row_name);
|
||||
}
|
||||
foreach (array_keys($dates) as $age) {
|
||||
$i = 0;
|
||||
foreach ($row_names as $row_name) {
|
||||
$rows[$i][] = idx(idx($row_array, $age), $row_name, '-');
|
||||
++$i;
|
||||
}
|
||||
}
|
||||
|
||||
$table = new AphrontTableView($rows);
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
'wide pri',
|
||||
));
|
||||
|
||||
$table->setHeaders(
|
||||
array_merge(
|
||||
array(
|
||||
'Metric',
|
||||
),
|
||||
array_keys($dates)));
|
||||
|
||||
return $table->render();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'view/base');
|
||||
phutil_require_module('phabricator', 'view/control/table');
|
||||
phutil_require_module('phabricator', 'view/utils');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DifferentialRevisionStatsView.php');
|
|
@ -143,6 +143,7 @@ abstract class DiffusionController extends PhabricatorController {
|
|||
|
||||
$view = id(new DifferentialRevisionListView())
|
||||
->setRevisions($revisions)
|
||||
->setFields(DifferentialRevisionListView::getDefaultFields())
|
||||
->setUser($this->getRequest()->getUser());
|
||||
|
||||
$phids = $view->getRequiredHandlePHIDs();
|
||||
|
|
|
@ -86,6 +86,9 @@ class DiffusionCommitController extends DiffusionController {
|
|||
$content[] = $detail_panel;
|
||||
}
|
||||
|
||||
$content[] = $this->buildAuditTable($commit);
|
||||
$content[] = $this->buildComments($commit);
|
||||
|
||||
$change_query = DiffusionPathChangeQuery::newFromDiffusionRequest(
|
||||
$drequest);
|
||||
$changes = $change_query->loadChanges();
|
||||
|
@ -213,6 +216,8 @@ class DiffusionCommitController extends DiffusionController {
|
|||
$content[] = $change_list;
|
||||
}
|
||||
|
||||
$content[] = $this->buildAddCommentView($commit);
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
$content,
|
||||
array(
|
||||
|
@ -290,4 +295,78 @@ class DiffusionCommitController extends DiffusionController {
|
|||
'</table>';
|
||||
}
|
||||
|
||||
private function buildAuditTable($commit) {
|
||||
$query = new PhabricatorAuditQuery();
|
||||
$query->withCommitPHIDs(array($commit->getPHID()));
|
||||
$audits = $query->execute();
|
||||
|
||||
$view = new PhabricatorAuditListView();
|
||||
$view->setAudits($audits);
|
||||
|
||||
$phids = $view->getRequiredHandlePHIDs();
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
|
||||
$view->setHandles($handles);
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader('Audits');
|
||||
$panel->appendChild($view);
|
||||
|
||||
return $panel;
|
||||
}
|
||||
|
||||
private function buildComments($commit) {
|
||||
$user = $this->getRequest()->getUser();
|
||||
$comments = id(new PhabricatorAuditComment())->loadAllWhere(
|
||||
'targetPHID = %s ORDER BY dateCreated ASC',
|
||||
$commit->getPHID());
|
||||
|
||||
$view = new DiffusionCommentListView();
|
||||
$view->setUser($user);
|
||||
$view->setComments($comments);
|
||||
|
||||
$phids = $view->getRequiredHandlePHIDs();
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
|
||||
$view->setHandles($handles);
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
private function buildAddCommentView($commit) {
|
||||
$user = $this->getRequest()->getUser();
|
||||
|
||||
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($user)
|
||||
->setAction('/audit/addcomment/')
|
||||
->addHiddenInput('commit', $commit->getPHID())
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setLabel('Action')
|
||||
->setName('action')
|
||||
->setOptions(PhabricatorAuditActionConstants::getActionNameMap()))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextAreaControl())
|
||||
->setLabel('Comments')
|
||||
->setName('content')
|
||||
->setCaption(phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => PhabricatorEnv::getDoclink(
|
||||
'article/Remarkup_Reference.html'),
|
||||
'tabindex' => '-1',
|
||||
'target' => '_blank',
|
||||
),
|
||||
'Formatting Reference')))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue($is_serious ? 'Submit' : 'Cook the Books'));
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader($is_serious ? 'Audit Commit' : 'Creative Accounting');
|
||||
$panel->appendChild($form);
|
||||
|
||||
return $panel;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,19 +6,29 @@
|
|||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/audit/constants/action');
|
||||
phutil_require_module('phabricator', 'applications/audit/query/audit');
|
||||
phutil_require_module('phabricator', 'applications/audit/storage/auditcomment');
|
||||
phutil_require_module('phabricator', 'applications/audit/view/list');
|
||||
phutil_require_module('phabricator', 'applications/differential/constants/changetype');
|
||||
phutil_require_module('phabricator', 'applications/differential/view/changesetlistview');
|
||||
phutil_require_module('phabricator', 'applications/diffusion/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/diffusion/data/pathchange');
|
||||
phutil_require_module('phabricator', 'applications/diffusion/query/contains/base');
|
||||
phutil_require_module('phabricator', 'applications/diffusion/query/pathchange/base');
|
||||
phutil_require_module('phabricator', 'applications/diffusion/view/commentlist');
|
||||
phutil_require_module('phabricator', 'applications/diffusion/view/commitchangetable');
|
||||
phutil_require_module('phabricator', 'applications/markup/engine');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'applications/repository/constants/repositorytype');
|
||||
phutil_require_module('phabricator', 'applications/repository/storage/repository');
|
||||
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
||||
phutil_require_module('phabricator', 'infrastructure/env');
|
||||
phutil_require_module('phabricator', 'storage/queryfx');
|
||||
phutil_require_module('phabricator', 'view/form/base');
|
||||
phutil_require_module('phabricator', 'view/form/control/select');
|
||||
phutil_require_module('phabricator', 'view/form/control/submit');
|
||||
phutil_require_module('phabricator', 'view/form/control/textarea');
|
||||
phutil_require_module('phabricator', 'view/form/error');
|
||||
phutil_require_module('phabricator', 'view/layout/panel');
|
||||
phutil_require_module('phabricator', 'view/utils');
|
||||
|
|
132
src/applications/diffusion/view/comment/DiffusionCommentView.php
Normal file
132
src/applications/diffusion/view/comment/DiffusionCommentView.php
Normal file
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class DiffusionCommentView extends AphrontView {
|
||||
|
||||
private $user;
|
||||
private $comment;
|
||||
private $commentNumber;
|
||||
private $handles;
|
||||
|
||||
public function setUser(PhabricatorUser $user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setComment(PhabricatorAuditComment $comment) {
|
||||
$this->comment = $comment;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCommentNumber($comment_number) {
|
||||
$this->commentNumber = $comment_number;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHandles(array $handles) {
|
||||
$this->handles = $handles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function getHandle($phid) {
|
||||
if (empty($this->handles[$phid])) {
|
||||
throw new Exception("Unloaded handle '{$phid}'!");
|
||||
}
|
||||
return $this->handles[$phid];
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$comment = $this->comment;
|
||||
$author = $this->getHandle($comment->getActorPHID());
|
||||
$author_link = $author->renderLink();
|
||||
|
||||
$actions = $this->renderActions();
|
||||
$content = $this->renderContent();
|
||||
$classes = $this->renderClasses();
|
||||
|
||||
$xaction_view = id(new PhabricatorTransactionView())
|
||||
->setUser($this->user)
|
||||
->setImageURI($author->getImageURI())
|
||||
->setActions($actions)
|
||||
->setAnchor('comment-'.$this->commentNumber, '#'.$this->commentNumber)
|
||||
->setEpoch($comment->getDateCreated())
|
||||
->appendChild($content);
|
||||
|
||||
foreach ($classes as $class) {
|
||||
$xaction_view->addClass($class);
|
||||
}
|
||||
|
||||
return $xaction_view;
|
||||
}
|
||||
|
||||
private function renderActions() {
|
||||
$comment = $this->comment;
|
||||
$author = $this->getHandle($comment->getActorPHID());
|
||||
$author_link = $author->renderLink();
|
||||
|
||||
$actions = array();
|
||||
switch ($comment->getAction()) {
|
||||
case PhabricatorAuditActionConstants::ACCEPT:
|
||||
$actions[] = "{$author_link} accepted this commit.";
|
||||
break;
|
||||
case PhabricatorAuditActionConstants::CONCERN:
|
||||
$actions[] = "{$author_link} raised concerns with this commit.";
|
||||
break;
|
||||
case PhabricatorAuditActionConstants::COMMENT:
|
||||
default:
|
||||
$actions[] = "{$author_link} commented on this commit.";
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($actions as $key => $action) {
|
||||
$actions[$key] = '<div>'.$action.'</div>';
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
private function renderContent() {
|
||||
$comment = $this->comment;
|
||||
|
||||
$engine = PhabricatorMarkupEngine::newDiffusionMarkupEngine();
|
||||
return
|
||||
'<div class="phabricator-remarkup">'.
|
||||
$engine->markupText($comment->getContent()).
|
||||
'</div>';
|
||||
}
|
||||
|
||||
private function renderClasses() {
|
||||
$comment = $this->comment;
|
||||
|
||||
$classes = array();
|
||||
switch ($comment->getAction()) {
|
||||
case PhabricatorAuditActionConstants::ACCEPT:
|
||||
$classes[] = 'audit-accept';
|
||||
break;
|
||||
case PhabricatorAuditActionConstants::CONCERN:
|
||||
$classes[] = 'audit-concern';
|
||||
break;
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
17
src/applications/diffusion/view/comment/__init__.php
Normal file
17
src/applications/diffusion/view/comment/__init__.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/audit/constants/action');
|
||||
phutil_require_module('phabricator', 'applications/markup/engine');
|
||||
phutil_require_module('phabricator', 'view/base');
|
||||
phutil_require_module('phabricator', 'view/layout/transaction');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DiffusionCommentView.php');
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class DiffusionCommentListView extends AphrontView {
|
||||
|
||||
private $user;
|
||||
private $comments;
|
||||
|
||||
public function setUser(PhabricatorUser $user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setComments(array $comments) {
|
||||
$this->comments = $comments;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRequiredHandlePHIDs() {
|
||||
$phids = array();
|
||||
foreach ($this->comments as $comment) {
|
||||
$phids[$comment->getActorPHID()] = true;
|
||||
}
|
||||
return array_keys($phids);
|
||||
}
|
||||
|
||||
public function setHandles(array $handles) {
|
||||
$this->handles = $handles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function render() {
|
||||
|
||||
$num = 1;
|
||||
|
||||
$comments = array();
|
||||
foreach ($this->comments as $comment) {
|
||||
$view = id(new DiffusionCommentView())
|
||||
->setComment($comment)
|
||||
->setCommentNumber($num)
|
||||
->setHandles($this->handles)
|
||||
->setUser($this->user);
|
||||
|
||||
$comments[] = $view->render();
|
||||
++$num;
|
||||
}
|
||||
|
||||
return
|
||||
'<div class="diffusion-comment-list">'.
|
||||
$this->renderSingleView($comments).
|
||||
'</div>';
|
||||
}
|
||||
|
||||
}
|
15
src/applications/diffusion/view/commentlist/__init__.php
Normal file
15
src/applications/diffusion/view/commentlist/__init__.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/diffusion/view/comment');
|
||||
phutil_require_module('phabricator', 'view/base');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('DiffusionCommentListView.php');
|
|
@ -20,9 +20,11 @@ class PhabricatorDirectoryMainController
|
|||
extends PhabricatorDirectoryController {
|
||||
|
||||
private $filter;
|
||||
private $subfilter;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->filter = idx($data, 'filter');
|
||||
$this->subfilter = idx($data, 'subfilter');
|
||||
}
|
||||
|
||||
public function shouldRequireAdmin() {
|
||||
|
@ -62,13 +64,17 @@ class PhabricatorDirectoryMainController
|
|||
}
|
||||
|
||||
private function buildMainResponse($nav, $projects) {
|
||||
$unbreak_panel = $this->buildUnbreakNowPanel();
|
||||
$triage_panel = $this->buildNeedsTriagePanel($projects);
|
||||
if (PhabricatorEnv::getEnvConfig('maniphest.enabled')) {
|
||||
$unbreak_panel = $this->buildUnbreakNowPanel();
|
||||
$triage_panel = $this->buildNeedsTriagePanel($projects);
|
||||
$tasks_panel = $this->buildTasksPanel();
|
||||
} else {
|
||||
$unbreak_panel = null;
|
||||
$triage_panel = null;
|
||||
$tasks_panel = null;
|
||||
}
|
||||
$jump_panel = $this->buildJumpPanel();
|
||||
$revision_panel = $this->buildRevisionPanel();
|
||||
$tasks_panel = $this->buildTasksPanel();
|
||||
$feed_view = $this->buildFeedView($projects, $is_full = false);
|
||||
|
||||
|
||||
$content = array(
|
||||
$unbreak_panel,
|
||||
|
@ -76,7 +82,6 @@ class PhabricatorDirectoryMainController
|
|||
$jump_panel,
|
||||
$revision_panel,
|
||||
$tasks_panel,
|
||||
$feed_view,
|
||||
);
|
||||
|
||||
$nav->appendChild($content);
|
||||
|
@ -103,17 +108,16 @@ class PhabricatorDirectoryMainController
|
|||
'/^d$/i' => 'uri:/differential/',
|
||||
'/^r$/i' => 'uri:/diffusion/',
|
||||
'/^t$/i' => 'uri:/maniphest/',
|
||||
'/^p$/i' => 'uri:/project/',
|
||||
'/^u$/i' => 'uri:/people/',
|
||||
'/r([A-Z]+)$/' => 'repository',
|
||||
'/r([A-Z]+)(\S+)$/' => 'commit',
|
||||
'/^d(\d+)$/i' => 'revision',
|
||||
'/^t(\d+)$/i' => 'task',
|
||||
|
||||
// TODO: '/^p$/i' => 'uri:/projects/',
|
||||
// TODO: '/^u$/i' => 'uri:/people/',
|
||||
// TODO: '/^p\s+(\S+)$/i' => 'project',
|
||||
// TODO: '/^u\s+(\S+)$/i' => 'user',
|
||||
// TODO: '/^task:\s+(\S+)/i' => 'create-task',
|
||||
// TODO: '/^(?:s|symbol)\s+(\S+)/i' => 'find-symbol',
|
||||
'/^p\s+(.+)$/i' => 'project',
|
||||
'/^u\s+(\S+)$/i' => 'user',
|
||||
'/^task:\s*(.+)/i' => 'create-task',
|
||||
'/^(?:s|symbol)\s+(\S+)/i' => 'find-symbol',
|
||||
);
|
||||
|
||||
|
||||
|
@ -137,6 +141,26 @@ class PhabricatorDirectoryMainController
|
|||
case 'task':
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/T'.$matches[1]);
|
||||
case 'user':
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/p/'.$matches[1].'/');
|
||||
case 'project':
|
||||
$project = PhabricatorProjectQueryUtil
|
||||
::findCloselyNamedProject($matches[1]);
|
||||
if ($project) {
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/project/view/'.$project->getID().'/');
|
||||
} else {
|
||||
$jump = $matches[1];
|
||||
}
|
||||
break;
|
||||
case 'find-symbol':
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/diffusion/symbol/'.$matches[1].'/?jump=true');
|
||||
case 'create-task':
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/maniphest/task/create/?title='
|
||||
.phutil_escape_uri($matches[1]));
|
||||
default:
|
||||
throw new Exception("Unknown jump effect '{$effect}'!");
|
||||
}
|
||||
|
@ -162,8 +186,29 @@ class PhabricatorDirectoryMainController
|
|||
}
|
||||
|
||||
private function buildFeedResponse($nav, $projects) {
|
||||
$view = $this->buildFeedView($projects, $is_full = true);
|
||||
$nav->appendChild($view);
|
||||
|
||||
$subnav = new AphrontSideNavFilterView();
|
||||
$subnav->setBaseURI(new PhutilURI('/feed/'));
|
||||
|
||||
$subnav->addFilter('all', 'All Activity', '/feed/');
|
||||
$subnav->addFilter('projects', 'My Projects');
|
||||
|
||||
$filter = $subnav->selectFilter($this->subfilter, 'all');
|
||||
|
||||
switch ($filter) {
|
||||
case 'all':
|
||||
$phids = array();
|
||||
break;
|
||||
case 'projects':
|
||||
$phids = mpull($projects, 'getPHID');
|
||||
break;
|
||||
}
|
||||
|
||||
$view = $this->buildFeedView($phids);
|
||||
$subnav->appendChild($view);
|
||||
|
||||
$nav->appendChild($subnav);
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
$nav,
|
||||
array(
|
||||
|
@ -286,8 +331,11 @@ class PhabricatorDirectoryMainController
|
|||
"View Active Revisions \xC2\xBB"));
|
||||
|
||||
if ($active) {
|
||||
$fields =
|
||||
|
||||
$revision_view = id(new DifferentialRevisionListView())
|
||||
->setRevisions($active)
|
||||
->setFields(DifferentialRevisionListView::getDefaultFields())
|
||||
->setUser($user);
|
||||
$phids = array_merge(
|
||||
array($user_phid),
|
||||
|
@ -362,16 +410,15 @@ class PhabricatorDirectoryMainController
|
|||
return $view;
|
||||
}
|
||||
|
||||
private function buildFeedView(array $projects, $is_full) {
|
||||
private function buildFeedView(array $phids) {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$user_phid = $user->getPHID();
|
||||
|
||||
$feed_query = new PhabricatorFeedQuery();
|
||||
$feed_query->setFilterPHIDs(
|
||||
array_merge(
|
||||
array($user_phid),
|
||||
mpull($projects, 'getPHID')));
|
||||
if ($phids) {
|
||||
$feed_query->setFilterPHIDs($phids);
|
||||
}
|
||||
|
||||
// TODO: All this limit stuff should probably be consolidated into the
|
||||
// feed query?
|
||||
|
@ -379,13 +426,9 @@ class PhabricatorDirectoryMainController
|
|||
$old_link = null;
|
||||
$new_link = null;
|
||||
|
||||
if ($is_full) {
|
||||
$feed_query->setAfter($request->getStr('after'));
|
||||
$feed_query->setBefore($request->getStr('before'));
|
||||
$limit = 500;
|
||||
} else {
|
||||
$limit = 100;
|
||||
}
|
||||
$feed_query->setAfter($request->getStr('after'));
|
||||
$feed_query->setBefore($request->getStr('before'));
|
||||
$limit = 500;
|
||||
|
||||
// Grab one more story than we intend to display so we can figure out
|
||||
// if we need to render an "Older Posts" link or not (with reasonable
|
||||
|
@ -394,12 +437,8 @@ class PhabricatorDirectoryMainController
|
|||
$feed = $feed_query->execute();
|
||||
$extra_row = (count($feed) == $limit + 1);
|
||||
|
||||
if ($is_full) {
|
||||
$have_new = ($request->getStr('before')) ||
|
||||
($request->getStr('after') && $extra_row);
|
||||
} else {
|
||||
$have_new = false;
|
||||
}
|
||||
$have_new = ($request->getStr('before')) ||
|
||||
($request->getStr('after') && $extra_row);
|
||||
|
||||
$have_old = ($request->getStr('after')) ||
|
||||
($request->getStr('before') && $extra_row) ||
|
||||
|
@ -412,7 +451,7 @@ class PhabricatorDirectoryMainController
|
|||
$old_link = phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/feed/?before='.end($feed)->getChronologicalKey(),
|
||||
'href' => '?before='.end($feed)->getChronologicalKey(),
|
||||
'class' => 'phabricator-feed-older-link',
|
||||
),
|
||||
"Older Stories \xC2\xBB");
|
||||
|
@ -421,7 +460,7 @@ class PhabricatorDirectoryMainController
|
|||
$new_link = phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/feed/?after='.reset($feed)->getChronologicalKey(),
|
||||
'href' => '?after='.reset($feed)->getChronologicalKey(),
|
||||
'class' => 'phabricator-feed-newer-link',
|
||||
),
|
||||
"\xC2\xAB Newer Stories");
|
||||
|
@ -466,7 +505,7 @@ class PhabricatorDirectoryMainController
|
|||
array(
|
||||
'href' => $doc_href,
|
||||
),
|
||||
'Jump Nav Use Guide');
|
||||
'Jump Nav User Guide');
|
||||
|
||||
$jump_input = phutil_render_tag(
|
||||
'input',
|
||||
|
@ -494,13 +533,17 @@ class PhabricatorDirectoryMainController
|
|||
),
|
||||
$jump_input));
|
||||
|
||||
$nav_buttons = array(
|
||||
'/maniphest/task/create/' => 'Create a Task',
|
||||
'/file/' => 'Upload a File',
|
||||
'/paste/' => 'Create Paste',
|
||||
'/w/' => 'Browse Wiki',
|
||||
'/diffusion/' => 'Browse Code',
|
||||
);
|
||||
$nav_buttons = array();
|
||||
|
||||
if (PhabricatorEnv::getEnvConfig('maniphest.enabled')) {
|
||||
$nav_buttons['/maniphest/task/create/'] = 'Create a Task';
|
||||
}
|
||||
$nav_buttons['/file/'] = 'Upload a File';
|
||||
$nav_buttons['/paste/'] = 'Create Paste';
|
||||
if (PhabricatorEnv::getEnvConfig('phriction.enabled')) {
|
||||
$nav_buttons['/w/'] = 'Browse Wiki';
|
||||
}
|
||||
$nav_buttons['/diffusion/'] = 'Browse Code';
|
||||
|
||||
$panel->appendChild('<div class="phabricator-jump-nav-buttons">');
|
||||
foreach ($nav_buttons as $uri => $name) {
|
||||
|
|
|
@ -18,6 +18,7 @@ phutil_require_module('phabricator', 'applications/maniphest/query');
|
|||
phutil_require_module('phabricator', 'applications/maniphest/view/tasklist');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'applications/project/query/project');
|
||||
phutil_require_module('phabricator', 'applications/project/query/util');
|
||||
phutil_require_module('phabricator', 'applications/search/storage/query');
|
||||
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
||||
phutil_require_module('phabricator', 'infrastructure/env');
|
||||
|
@ -25,8 +26,10 @@ phutil_require_module('phabricator', 'infrastructure/javelin/api');
|
|||
phutil_require_module('phabricator', 'infrastructure/javelin/markup');
|
||||
phutil_require_module('phabricator', 'view/layout/minipanel');
|
||||
phutil_require_module('phabricator', 'view/layout/panel');
|
||||
phutil_require_module('phabricator', 'view/layout/sidenavfilter');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'parser/uri');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -237,6 +237,7 @@ class PhabricatorFileListController extends PhabricatorFileController {
|
|||
$rowc[] = '';
|
||||
}
|
||||
|
||||
$name = $file->getName();
|
||||
$rows[] = array(
|
||||
phutil_escape_html('F'.$file->getID()),
|
||||
$file->getAuthorPHID()
|
||||
|
@ -247,7 +248,7 @@ class PhabricatorFileListController extends PhabricatorFileController {
|
|||
array(
|
||||
'href' => $file->getBestURI(),
|
||||
),
|
||||
phutil_escape_html($file->getName())),
|
||||
($name != '' ? phutil_escape_html($name) : '<em>no name</em>')),
|
||||
phutil_escape_html(number_format($file->getByteSize()).' bytes'),
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @group maniphest
|
||||
*/
|
||||
final class ManiphestBatchEditController extends ManiphestController {
|
||||
|
||||
public function processRequest() {
|
||||
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$task_ids = $request->getArr('batch');
|
||||
$tasks = id(new ManiphestTask())->loadAllWhere(
|
||||
'id IN (%Ld)',
|
||||
$task_ids);
|
||||
|
||||
$actions = $request->getStr('actions');
|
||||
if ($actions) {
|
||||
$actions = json_decode($actions, true);
|
||||
}
|
||||
|
||||
if ($request->isFormPost() && is_array($actions)) {
|
||||
foreach ($tasks as $task) {
|
||||
$xactions = $this->buildTransactions($actions, $task);
|
||||
if ($xactions) {
|
||||
$editor = new ManiphestTransactionEditor();
|
||||
$editor->applyTransactions($task, $xactions);
|
||||
}
|
||||
}
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/maniphest/');
|
||||
}
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader('Maniphest Batch Editor');
|
||||
|
||||
$handle_phids = mpull($tasks, 'getOwnerPHID');
|
||||
$handles = id(new PhabricatorObjectHandleData($handle_phids))
|
||||
->loadHandles();
|
||||
|
||||
$list = new ManiphestTaskListView();
|
||||
$list->setTasks($tasks);
|
||||
$list->setUser($user);
|
||||
$list->setHandles($handles);
|
||||
|
||||
$template = new AphrontTokenizerTemplateView();
|
||||
$template = $template->render();
|
||||
|
||||
require_celerity_resource('maniphest-batch-editor');
|
||||
Javelin::initBehavior(
|
||||
'maniphest-batch-editor',
|
||||
array(
|
||||
'root' => 'maniphest-batch-edit-form',
|
||||
'tokenizerTemplate' => $template,
|
||||
'sources' => array(
|
||||
'project' => '/typeahead/common/projects/',
|
||||
),
|
||||
'input' => 'batch-form-actions',
|
||||
));
|
||||
|
||||
$form = new AphrontFormView();
|
||||
$form->setUser($user);
|
||||
$form->setID('maniphest-batch-edit-form');
|
||||
|
||||
foreach ($tasks as $task) {
|
||||
$form->appendChild(
|
||||
phutil_render_tag(
|
||||
'input',
|
||||
array(
|
||||
'type' => 'hidden',
|
||||
'name' => 'batch[]',
|
||||
'value' => $task->getID(),
|
||||
),
|
||||
null));
|
||||
}
|
||||
|
||||
$form->appendChild(
|
||||
phutil_render_tag(
|
||||
'input',
|
||||
array(
|
||||
'type' => 'hidden',
|
||||
'name' => 'actions',
|
||||
'id' => 'batch-form-actions',
|
||||
),
|
||||
null));
|
||||
$form->appendChild('<p>These tasks will be edited:</p>');
|
||||
$form->appendChild($list);
|
||||
$form->appendChild(
|
||||
'<h1>Actions</h1>'.
|
||||
'<div class="aphront-form-inset">'.
|
||||
'<div style="float: right;">'.
|
||||
javelin_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '#',
|
||||
'class' => 'button green',
|
||||
'sigil' => 'add-action',
|
||||
'mustcapture' => true,
|
||||
),
|
||||
'Add Another Action').
|
||||
'</div>'.
|
||||
'<div style="clear: both;"></div>'.
|
||||
javelin_render_tag(
|
||||
'table',
|
||||
array(
|
||||
'sigil' => 'maniphest-batch-actions',
|
||||
'class' => 'maniphest-batch-actions-table',
|
||||
),
|
||||
'').
|
||||
'</div>')
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue('Update Tasks')
|
||||
->addCancelButton('/maniphest/', 'Done'));
|
||||
|
||||
$panel->appendChild($form);
|
||||
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
$panel,
|
||||
array(
|
||||
'title' => 'Batch Editor',
|
||||
));
|
||||
}
|
||||
|
||||
private function buildTransactions($actions, ManiphestTask $task) {
|
||||
$template = new ManiphestTransaction();
|
||||
$template->setAuthorPHID($this->getRequest()->getUser()->getPHID());
|
||||
|
||||
// TODO: Set content source to "batch edit".
|
||||
|
||||
$xactions = array();
|
||||
foreach ($actions as $action) {
|
||||
$value = $action['value'];
|
||||
switch ($action['action']) {
|
||||
case 'add_project':
|
||||
case 'remove_project':
|
||||
|
||||
$is_remove = ($action['action'] == 'remove_project');
|
||||
|
||||
$current = array_fill_keys($task->getProjectPHIDs(), true);
|
||||
$value = array_fill_keys($value, true);
|
||||
|
||||
$new = $current;
|
||||
$did_something = false;
|
||||
|
||||
if ($is_remove) {
|
||||
foreach ($value as $phid => $ignored) {
|
||||
if (isset($new[$phid])) {
|
||||
unset($new[$phid]);
|
||||
$did_something = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($value as $phid => $ignored) {
|
||||
if (empty($new[$phid])) {
|
||||
$new[$phid] = true;
|
||||
$did_something = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$did_something) {
|
||||
break;
|
||||
}
|
||||
|
||||
$new = array_keys($new);
|
||||
$xaction = clone $template;
|
||||
$xaction->setTransactionType(ManiphestTransactionType::TYPE_PROJECTS);
|
||||
$xaction->setNewValue($new);
|
||||
$xactions[] = $xaction;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $xactions;
|
||||
}
|
||||
|
||||
}
|
29
src/applications/maniphest/controller/batch/__init__.php
Normal file
29
src/applications/maniphest/controller/batch/__init__.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/response/redirect');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/constants/transactiontype');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/editor/transaction');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/storage/task');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/storage/transaction');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/view/tasklist');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
||||
phutil_require_module('phabricator', 'infrastructure/javelin/api');
|
||||
phutil_require_module('phabricator', 'infrastructure/javelin/markup');
|
||||
phutil_require_module('phabricator', 'view/control/tokenizer');
|
||||
phutil_require_module('phabricator', 'view/form/base');
|
||||
phutil_require_module('phabricator', 'view/form/control/submit');
|
||||
phutil_require_module('phabricator', 'view/layout/panel');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('ManiphestBatchEditController.php');
|
|
@ -222,20 +222,35 @@ class ManiphestTaskListController extends ManiphestController {
|
|||
"Displaying tasks {$cur} - {$max} of {$tot}.".
|
||||
'</div>');
|
||||
|
||||
$selector = new AphrontNullView();
|
||||
|
||||
foreach ($tasks as $group => $list) {
|
||||
$task_list = new ManiphestTaskListView();
|
||||
$task_list->setShowBatchControls(true);
|
||||
$task_list->setUser($user);
|
||||
$task_list->setTasks($list);
|
||||
$task_list->setHandles($handles);
|
||||
|
||||
$count = number_format(count($list));
|
||||
$nav->appendChild(
|
||||
$selector->appendChild(
|
||||
'<h1 class="maniphest-task-group-header">'.
|
||||
phutil_escape_html($group).' ('.$count.')'.
|
||||
'</h1>');
|
||||
$nav->appendChild($task_list);
|
||||
$selector->appendChild($task_list);
|
||||
}
|
||||
|
||||
|
||||
$selector->appendChild($this->renderBatchEditor());
|
||||
|
||||
$selector = phabricator_render_form(
|
||||
$user,
|
||||
array(
|
||||
'method' => 'POST',
|
||||
'action' => '/maniphest/batch/',
|
||||
),
|
||||
$selector->render());
|
||||
|
||||
$nav->appendChild($selector);
|
||||
$nav->appendChild($pager);
|
||||
}
|
||||
|
||||
|
@ -479,4 +494,61 @@ class ManiphestTaskListController extends ManiphestController {
|
|||
return implode("\n", $links);
|
||||
}
|
||||
|
||||
private function renderBatchEditor() {
|
||||
Javelin::initBehavior(
|
||||
'maniphest-batch-selector',
|
||||
array(
|
||||
'selectAll' => 'batch-select-all',
|
||||
'selectNone' => 'batch-select-none',
|
||||
'submit' => 'batch-select-submit',
|
||||
'status' => 'batch-select-status-cell',
|
||||
));
|
||||
|
||||
$select_all = javelin_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '#',
|
||||
'mustcapture' => true,
|
||||
'class' => 'grey button',
|
||||
'id' => 'batch-select-all',
|
||||
),
|
||||
'Select All');
|
||||
|
||||
$select_none = javelin_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '#',
|
||||
'mustcapture' => true,
|
||||
'class' => 'grey button',
|
||||
'id' => 'batch-select-none',
|
||||
),
|
||||
'Clear Selection');
|
||||
|
||||
$submit = phutil_render_tag(
|
||||
'button',
|
||||
array(
|
||||
'id' => 'batch-select-submit',
|
||||
'disabled' => 'disabled',
|
||||
'class' => 'disabled',
|
||||
),
|
||||
'Batch Edit Selected Tasks »');
|
||||
|
||||
return
|
||||
'<div class="maniphest-batch-editor">'.
|
||||
'<div class="batch-editor-header">Batch Task Editor</div>'.
|
||||
'<table class="maniphest-batch-editor-layout">'.
|
||||
'<tr>'.
|
||||
'<td>'.
|
||||
$select_all.
|
||||
$select_none.
|
||||
'</td>'.
|
||||
'<td id="batch-select-status-cell">'.
|
||||
'0 Selected Tasks'.
|
||||
'</td>'.
|
||||
'<td class="batch-select-submit-cell">'.$submit.'</td>'.
|
||||
'</tr>'.
|
||||
'</table>'.
|
||||
'</table>';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ phutil_require_module('phabricator', 'applications/maniphest/query');
|
|||
phutil_require_module('phabricator', 'applications/maniphest/view/tasklist');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
||||
phutil_require_module('phabricator', 'infrastructure/javelin/api');
|
||||
phutil_require_module('phabricator', 'infrastructure/javelin/markup');
|
||||
phutil_require_module('phabricator', 'view/control/pager');
|
||||
phutil_require_module('phabricator', 'view/form/base');
|
||||
phutil_require_module('phabricator', 'view/form/control/submit');
|
||||
|
@ -22,6 +24,7 @@ phutil_require_module('phabricator', 'view/form/control/togglebuttons');
|
|||
phutil_require_module('phabricator', 'view/form/control/tokenizer');
|
||||
phutil_require_module('phabricator', 'view/layout/listfilter');
|
||||
phutil_require_module('phabricator', 'view/layout/sidenavfilter');
|
||||
phutil_require_module('phabricator', 'view/null');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'parser/uri');
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -253,6 +253,8 @@ class ManiphestTransactionEditor {
|
|||
$prefix = $this->getSubjectPrefix();
|
||||
$subject = trim("{$prefix} [{$action}] T{$task_id}: {$title}");
|
||||
|
||||
$mailtags = $this->getMailTags($transactions);
|
||||
|
||||
$template = id(new PhabricatorMetaMTAMail())
|
||||
->setSubject($subject)
|
||||
->setFrom($transaction->getAuthorPHID())
|
||||
|
@ -261,6 +263,7 @@ class ManiphestTransactionEditor {
|
|||
->setThreadID($thread_id, $is_create)
|
||||
->setRelatedPHID($task->getPHID())
|
||||
->setIsBulk(true)
|
||||
->setMailTags($mailtags)
|
||||
->setBody($body);
|
||||
|
||||
$mails = $reply_handler->multiplexMail(
|
||||
|
@ -349,4 +352,30 @@ class ManiphestTransactionEditor {
|
|||
return $is_create;
|
||||
}
|
||||
|
||||
private function getMailTags(array $transactions) {
|
||||
$tags = array();
|
||||
foreach ($transactions as $xaction) {
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case ManiphestTransactionType::TYPE_CCS:
|
||||
$tags[] = MetaMTANotificationType::TYPE_MANIPHEST_CC;
|
||||
break;
|
||||
case ManiphestTransactionType::TYPE_PROJECTS:
|
||||
$tags[] = MetaMTANotificationType::TYPE_MANIPHEST_PROJECTS;
|
||||
break;
|
||||
case ManiphestTransactionType::TYPE_PRIORITY:
|
||||
$tags[] = MetaMTANotificationType::TYPE_MANIPHEST_PRIORITY;
|
||||
break;
|
||||
default:
|
||||
$tags[] = MetaMTANotificationType::TYPE_MANIPHEST_OTHER;
|
||||
break;
|
||||
}
|
||||
|
||||
if ($xaction->hasComments()) {
|
||||
$tags[] = MetaMTANotificationType::TYPE_MANIPHEST_COMMENT;
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique($tags);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ phutil_require_module('phabricator', 'applications/maniphest/constants/action');
|
|||
phutil_require_module('phabricator', 'applications/maniphest/constants/status');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/constants/transactiontype');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/view/transactiondetail');
|
||||
phutil_require_module('phabricator', 'applications/metamta/constants/notificationtype');
|
||||
phutil_require_module('phabricator', 'applications/metamta/storage/mail');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'applications/search/index/indexer/maniphest');
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -24,6 +24,7 @@ class ManiphestTaskListView extends ManiphestView {
|
|||
private $tasks;
|
||||
private $handles;
|
||||
private $user;
|
||||
private $showBatchControls;
|
||||
|
||||
public function setTasks(array $tasks) {
|
||||
$this->tasks = $tasks;
|
||||
|
@ -40,12 +41,18 @@ class ManiphestTaskListView extends ManiphestView {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function setShowBatchControls($show_batch_controls) {
|
||||
$this->showBatchControls = $show_batch_controls;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
|
||||
$views = array();
|
||||
foreach ($this->tasks as $task) {
|
||||
$view = new ManiphestTaskSummaryView();
|
||||
$view->setTask($task);
|
||||
$view->setShowBatchControls($this->showBatchControls);
|
||||
$view->setUser($this->user);
|
||||
$view->setHandles($this->handles);
|
||||
$views[] = $view->render();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -24,6 +24,7 @@ class ManiphestTaskSummaryView extends ManiphestView {
|
|||
private $task;
|
||||
private $handles;
|
||||
private $user;
|
||||
private $showBatchControls;
|
||||
|
||||
public function setTask(ManiphestTask $task) {
|
||||
$this->task = $task;
|
||||
|
@ -40,6 +41,11 @@ class ManiphestTaskSummaryView extends ManiphestView {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function setShowBatchControls($show_batch_controls) {
|
||||
$this->showBatchControls = $show_batch_controls;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
|
||||
if (!$this->user) {
|
||||
|
@ -63,36 +69,58 @@ class ManiphestTaskSummaryView extends ManiphestView {
|
|||
$pri_class = idx($classes, $task->getPriority());
|
||||
$status_map = ManiphestTaskStatus::getTaskStatusMap();
|
||||
|
||||
return
|
||||
'<table class="maniphest-task-summary">'.
|
||||
'<tr>'.
|
||||
'<td class="maniphest-task-number '.$pri_class.'">'.
|
||||
'T'.$task->getID().
|
||||
'</td>'.
|
||||
'<td class="maniphest-task-status">'.
|
||||
idx($status_map, $task->getStatus(), 'Unknown').
|
||||
'</td>'.
|
||||
'<td class="maniphest-task-owner">'.
|
||||
($task->getOwnerPHID()
|
||||
? $handles[$task->getOwnerPHID()]->renderLink()
|
||||
: '<em>None</em>').
|
||||
'</td>'.
|
||||
'<td class="maniphest-task-name">'.
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/T'.$task->getID(),
|
||||
),
|
||||
phutil_escape_html($task->getTitle())).
|
||||
'</td>'.
|
||||
'<td class="maniphest-task-priority">'.
|
||||
ManiphestTaskPriority::getTaskPriorityName($task->getPriority()).
|
||||
'</td>'.
|
||||
'<td class="maniphest-task-updated">'.
|
||||
phabricator_datetime($task->getDateModified(), $this->user).
|
||||
'</td>'.
|
||||
'</tr>'.
|
||||
'</table>';
|
||||
$batch = null;
|
||||
if ($this->showBatchControls) {
|
||||
$batch =
|
||||
'<td class="maniphest-task-batch">'.
|
||||
javelin_render_tag(
|
||||
'input',
|
||||
array(
|
||||
'type' => 'checkbox',
|
||||
'name' => 'batch[]',
|
||||
'value' => $task->getID(),
|
||||
'sigil' => 'maniphest-batch',
|
||||
),
|
||||
null).
|
||||
'</td>';
|
||||
}
|
||||
|
||||
return javelin_render_tag(
|
||||
'table',
|
||||
array(
|
||||
'class' => 'maniphest-task-summary',
|
||||
'sigil' => 'maniphest-task',
|
||||
),
|
||||
'<tr>'.
|
||||
'<td class="maniphest-task-handle '.$pri_class.'">'.
|
||||
'</td>'.
|
||||
$batch.
|
||||
'<td class="maniphest-task-number">'.
|
||||
'T'.$task->getID().
|
||||
'</td>'.
|
||||
'<td class="maniphest-task-status">'.
|
||||
idx($status_map, $task->getStatus(), 'Unknown').
|
||||
'</td>'.
|
||||
'<td class="maniphest-task-owner">'.
|
||||
($task->getOwnerPHID()
|
||||
? $handles[$task->getOwnerPHID()]->renderLink()
|
||||
: '<em>None</em>').
|
||||
'</td>'.
|
||||
'<td class="maniphest-task-name">'.
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/T'.$task->getID(),
|
||||
),
|
||||
phutil_escape_html($task->getTitle())).
|
||||
'</td>'.
|
||||
'<td class="maniphest-task-priority">'.
|
||||
ManiphestTaskPriority::getTaskPriorityName($task->getPriority()).
|
||||
'</td>'.
|
||||
'<td class="maniphest-task-updated">'.
|
||||
phabricator_datetime($task->getDateModified(), $this->user).
|
||||
'</td>'.
|
||||
'</tr>');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ phutil_require_module('phabricator', 'applications/maniphest/constants/priority'
|
|||
phutil_require_module('phabricator', 'applications/maniphest/constants/status');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/view/base');
|
||||
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
||||
phutil_require_module('phabricator', 'infrastructure/javelin/markup');
|
||||
phutil_require_module('phabricator', 'view/utils');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
|
|
|
@ -173,14 +173,11 @@ class ManiphestTransactionDetailView extends ManiphestView {
|
|||
),
|
||||
$author->renderLink().' '.$desc.'.'.$full_summary);
|
||||
}
|
||||
$descs = implode("\n", $descs);
|
||||
|
||||
if ($this->getRenderSummaryOnly()) {
|
||||
return $descs;
|
||||
return implode("\n", $descs);
|
||||
}
|
||||
|
||||
$more_classes = implode(' ', $more_classes);
|
||||
|
||||
if ($comment_transaction && $comment_transaction->hasComments()) {
|
||||
$comments = $comment_transaction->getCache();
|
||||
if (!strlen($comments)) {
|
||||
|
@ -203,58 +200,33 @@ class ManiphestTransactionDetailView extends ManiphestView {
|
|||
$comment_block = null;
|
||||
}
|
||||
|
||||
if ($this->preview) {
|
||||
$timestamp = 'COMMENT PREVIEW';
|
||||
} else {
|
||||
$timestamp = phabricator_datetime(
|
||||
$transaction->getDateCreated(),
|
||||
$this->user);
|
||||
}
|
||||
|
||||
$info = array();
|
||||
|
||||
$source_transaction = nonempty($comment_transaction, $any_transaction);
|
||||
$content_source = new PhabricatorContentSourceView();
|
||||
$content_source->setContentSource($source_transaction->getContentSource());
|
||||
$content_source->setUser($this->user);
|
||||
$info[] = $content_source->render();
|
||||
|
||||
$info[] = $timestamp;
|
||||
$xaction_view = id(new PhabricatorTransactionView())
|
||||
->setUser($this->user)
|
||||
->setImageURI($author->getImageURI())
|
||||
->setContentSource($source_transaction->getContentSource())
|
||||
->setActions($descs);
|
||||
|
||||
$comment_anchor = null;
|
||||
$num = $this->commentNumber;
|
||||
if ($num && !$this->preview) {
|
||||
Javelin::initBehavior('phabricator-watch-anchor');
|
||||
$anchor_name = 'comment-'.$num;
|
||||
$info[] = javelin_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'name' => $anchor_name,
|
||||
'id' => $anchor_name,
|
||||
'href' => '#'.$anchor_name,
|
||||
),
|
||||
'T'.$any_transaction->getTaskID().'#'.$anchor_name);
|
||||
$comment_anchor = 'anchor-'.$anchor_name;
|
||||
foreach ($more_classes as $class) {
|
||||
$xaction_view->addClass($class);
|
||||
}
|
||||
|
||||
$info = implode(' · ', array_filter($info));
|
||||
if ($this->preview) {
|
||||
$xaction_view->setIsPreview($this->preview);
|
||||
} else {
|
||||
$xaction_view->setEpoch($any_transaction->getDateCreated());
|
||||
if ($this->commentNumber) {
|
||||
$anchor_name = 'comment-'.$this->commentNumber;
|
||||
$anchor_text = 'T'.$any_transaction->getTaskID().'#'.$anchor_name;
|
||||
|
||||
return phutil_render_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => "maniphest-transaction-detail-container",
|
||||
'style' => "background-image: url('".$author->getImageURI()."')",
|
||||
'id' => $comment_anchor,
|
||||
),
|
||||
'<div class="maniphest-transaction-detail-view '.$more_classes.'">'.
|
||||
'<div class="maniphest-transaction-header">'.
|
||||
'<div class="maniphest-transaction-timestamp">'.
|
||||
$info.
|
||||
'</div>'.
|
||||
$descs.
|
||||
'</div>'.
|
||||
$comment_block.
|
||||
'</div>');
|
||||
$xaction_view->setAnchor($anchor_name, $anchor_text);
|
||||
}
|
||||
}
|
||||
|
||||
$xaction_view->appendChild($comment_block);
|
||||
|
||||
return $xaction_view->render();
|
||||
}
|
||||
|
||||
private function renderSupplementalInfoForEmail($transaction) {
|
||||
|
|
|
@ -12,14 +12,13 @@ phutil_require_module('phabricator', 'applications/maniphest/constants/priority'
|
|||
phutil_require_module('phabricator', 'applications/maniphest/constants/status');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/constants/transactiontype');
|
||||
phutil_require_module('phabricator', 'applications/maniphest/view/base');
|
||||
phutil_require_module('phabricator', 'applications/metamta/contentsource/view');
|
||||
phutil_require_module('phabricator', 'applications/phid/constants');
|
||||
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
||||
phutil_require_module('phabricator', 'infrastructure/diff/engine');
|
||||
phutil_require_module('phabricator', 'infrastructure/env');
|
||||
phutil_require_module('phabricator', 'infrastructure/javelin/api');
|
||||
phutil_require_module('phabricator', 'infrastructure/javelin/markup');
|
||||
phutil_require_module('phabricator', 'view/utils');
|
||||
phutil_require_module('phabricator', 'view/layout/transaction');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
|
|
@ -59,6 +59,11 @@ class PhabricatorMarkupEngine {
|
|||
));
|
||||
}
|
||||
|
||||
public static function newDiffusionMarkupEngine(array $options = array()) {
|
||||
return self::newMarkupEngine(array(
|
||||
));
|
||||
}
|
||||
|
||||
public static function newProfileMarkupEngine() {
|
||||
return self::newMarkupEngine(array(
|
||||
));
|
||||
|
|
21
src/applications/metamta/constants/base/MetaMTAConstants.php
Normal file
21
src/applications/metamta/constants/base/MetaMTAConstants.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
abstract class MetaMTAConstants {
|
||||
|
||||
}
|
10
src/applications/metamta/constants/base/__init__.php
Normal file
10
src/applications/metamta/constants/base/__init__.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
phutil_require_source('MetaMTAConstants.php');
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class MetaMTANotificationType
|
||||
extends MetaMTAConstants {
|
||||
|
||||
const TYPE_DIFFERENTIAL_COMMITTED = 'differential-committed';
|
||||
const TYPE_DIFFERENTIAL_CC = 'differential-cc';
|
||||
const TYPE_DIFFERENTIAL_COMMENT = 'differential-comment';
|
||||
|
||||
const TYPE_MANIPHEST_PROJECTS = 'maniphest-projects';
|
||||
const TYPE_MANIPHEST_PRIORITY = 'maniphest-priority';
|
||||
const TYPE_MANIPHEST_CC = 'maniphest-cc';
|
||||
const TYPE_MANIPHEST_OTHER = 'maniphest-other';
|
||||
const TYPE_MANIPHEST_COMMENT = 'maniphest-comment';
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue