mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 23:02:42 +01:00
Adding Ponder-related files.
Summary: Ponder is similar in spirit to the Wiki tool, but uses a Q&A format and up/downvotes to signal user sentiment. Popular questions are moved to the top of the feed on a 5-minute cycle based on age (younger is better) and vote count (higher is better). Pre-apologies for noob diff. Test Plan: - `./bin/phd list` Should include `PonderHeatDaemon`; phd launch it if necessary. - Navigate to /ponder/ ; observe sanity when adding questions, voting on them, and adding answers. - Confirm that questions and answers are linkable using Q5 / Q5#A5 formatted object links. - Confirm that searching for Ponder Questions works using built-in search. Feedback on code / schema / whatever organization very welcome. Reviewers: nh, vrana, epriestley Reviewed By: epriestley CC: gmarcotte, aran, Korvin, starruler Differential Revision: https://secure.phabricator.com/D3136
This commit is contained in:
parent
9030fe8b09
commit
64472dd7b8
50 changed files with 3204 additions and 51 deletions
50
resources/sql/patches/ponder.sql
Normal file
50
resources/sql/patches/ponder.sql
Normal file
|
@ -0,0 +1,50 @@
|
|||
CREATE TABLE `{$NAMESPACE}_ponder`.`ponder_question` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`title` varchar(255) NOT NULL,
|
||||
`phid` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
|
||||
`voteCount` int(10) NOT NULL,
|
||||
`authorPHID` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
|
||||
`content` longtext CHARACTER SET utf8 NOT NULL,
|
||||
`dateCreated` int(10) unsigned NOT NULL,
|
||||
`dateModified` int(10) unsigned NOT NULL,
|
||||
`contentSource` varchar(255) DEFAULT NULL,
|
||||
`heat` float NOT NULL,
|
||||
`answerCount` int(10) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `phid` (`phid`),
|
||||
KEY `authorPHID` (`authorPHID`),
|
||||
KEY `heat` (`heat`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `{$NAMESPACE}_ponder`.`ponder_answer` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`questionID` int(10) unsigned NOT NULL,
|
||||
`phid` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
|
||||
`voteCount` int(10) NOT NULL,
|
||||
`authorPHID` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
|
||||
`content` longtext CHARACTER SET utf8 NOT NULL,
|
||||
`dateCreated` int(10) unsigned NOT NULL,
|
||||
`dateModified` int(10) unsigned NOT NULL,
|
||||
`contentSource` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `phid` (`phid`),
|
||||
KEY `questionID` (`questionID`),
|
||||
KEY `authorPHID` (`authorPHID`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `{$NAMESPACE}_ponder`.`edge` (
|
||||
`src` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
|
||||
`type` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
|
||||
`dst` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
|
||||
`dateCreated` int(10) unsigned NOT NULL,
|
||||
`seq` int(10) unsigned NOT NULL,
|
||||
`dataID` int(10) unsigned DEFAULT NULL,
|
||||
PRIMARY KEY (`src`,`type`,`dst`),
|
||||
KEY `src` (`src`,`type`,`dateCreated`,`seq`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `{$NAMESPACE}_ponder`.`edgedata` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`data` longtext CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
@ -63,6 +63,13 @@ celerity_register_resource_map(array(
|
|||
'disk' => '/rsrc/image/app/app_phriction.png',
|
||||
'type' => 'png',
|
||||
),
|
||||
'/rsrc/image/app/app_ponder.png' =>
|
||||
array(
|
||||
'hash' => '9893ca3674af96884d3564ecbe101280',
|
||||
'uri' => '/res/9893ca36/rsrc/image/app/app_ponder.png',
|
||||
'disk' => '/rsrc/image/app/app_ponder.png',
|
||||
'type' => 'png',
|
||||
),
|
||||
'/rsrc/image/app/app_settings.png' =>
|
||||
array(
|
||||
'hash' => '095fa0e61ec11d3f7e543ba48f5a5adb',
|
||||
|
@ -70,10 +77,24 @@ celerity_register_resource_map(array(
|
|||
'disk' => '/rsrc/image/app/app_settings.png',
|
||||
'type' => 'png',
|
||||
),
|
||||
'/rsrc/image/application/ponder/downvote.png' =>
|
||||
array(
|
||||
'hash' => '46c5644a0fccb9e237a3363e07f50487',
|
||||
'uri' => '/res/46c5644a/rsrc/image/application/ponder/downvote.png',
|
||||
'disk' => '/rsrc/image/application/ponder/downvote.png',
|
||||
'type' => 'png',
|
||||
),
|
||||
'/rsrc/image/application/ponder/upvote.png' =>
|
||||
array(
|
||||
'hash' => 'edd58ed3a09f3017c78601b1a5d0e7a7',
|
||||
'uri' => '/res/edd58ed3/rsrc/image/application/ponder/upvote.png',
|
||||
'disk' => '/rsrc/image/application/ponder/upvote.png',
|
||||
'type' => 'png',
|
||||
),
|
||||
'/rsrc/image/apps.png' =>
|
||||
array(
|
||||
'hash' => 'f7cb4abeb73245fea4098a02fd784653',
|
||||
'uri' => '/res/f7cb4abe/rsrc/image/apps.png',
|
||||
'hash' => '134f6ac3d63e24070bf7a11b294ca72c',
|
||||
'uri' => '/res/134f6ac3/rsrc/image/apps.png',
|
||||
'disk' => '/rsrc/image/apps.png',
|
||||
'type' => 'png',
|
||||
),
|
||||
|
@ -1608,6 +1629,32 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/js/application/phriction/phriction-document-preview.js',
|
||||
),
|
||||
'javelin-behavior-ponder-feedback-preview' =>
|
||||
array(
|
||||
'uri' => '/res/2e802dd9/rsrc/js/application/ponder/behavior-comment-preview.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-dom',
|
||||
2 => 'javelin-util',
|
||||
3 => 'phabricator-shaped-request',
|
||||
),
|
||||
'disk' => '/rsrc/js/application/ponder/behavior-comment-preview.js',
|
||||
),
|
||||
'javelin-behavior-ponder-votebox' =>
|
||||
array(
|
||||
'uri' => '/res/6517d3f5/rsrc/js/application/ponder/behavior-votebox.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-behavior',
|
||||
1 => 'javelin-dom',
|
||||
2 => 'javelin-util',
|
||||
3 => 'phabricator-shaped-request',
|
||||
),
|
||||
'disk' => '/rsrc/js/application/ponder/behavior-votebox.js',
|
||||
),
|
||||
'javelin-behavior-project-create' =>
|
||||
array(
|
||||
'uri' => '/res/e91f3f8f/rsrc/js/application/projects/behavior-project-create.js',
|
||||
|
@ -1635,7 +1682,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'javelin-behavior-repository-crossreference' =>
|
||||
array(
|
||||
'uri' => '/res/e0d58d3b/rsrc/js/application/repository/repository-crossreference.js',
|
||||
'uri' => '/res/12700384/rsrc/js/application/repository/repository-crossreference.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -2200,7 +2247,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'phabricator-app-buttons-css' =>
|
||||
array(
|
||||
'uri' => '/res/1e153463/rsrc/css/application/directory/phabricator-app-buttons.css',
|
||||
'uri' => '/res/2d5d414c/rsrc/css/application/directory/phabricator-app-buttons.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -2730,6 +2777,42 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/css/application/phriction/phriction-document-css.css',
|
||||
),
|
||||
'ponder-core-view-css' =>
|
||||
array(
|
||||
'uri' => '/res/4a6e2fc7/rsrc/css/application/ponder/core.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
'disk' => '/rsrc/css/application/ponder/core.css',
|
||||
),
|
||||
'ponder-feed-view-css' =>
|
||||
array(
|
||||
'uri' => '/res/df22bd20/rsrc/css/application/ponder/feed.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
'disk' => '/rsrc/css/application/ponder/feed.css',
|
||||
),
|
||||
'ponder-post-css' =>
|
||||
array(
|
||||
'uri' => '/res/32c960df/rsrc/css/application/ponder/post.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
'disk' => '/rsrc/css/application/ponder/post.css',
|
||||
),
|
||||
'ponder-vote-css' =>
|
||||
array(
|
||||
'uri' => '/res/923bcf97/rsrc/css/application/ponder/vote.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
'disk' => '/rsrc/css/application/ponder/vote.css',
|
||||
),
|
||||
'raphael-core' =>
|
||||
array(
|
||||
'uri' => '/res/3f48575a/rsrc/js/raphael/raphael.js',
|
||||
|
@ -2777,7 +2860,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'syntax-highlighting-css' =>
|
||||
array(
|
||||
'uri' => '/res/5669beb6/rsrc/css/core/syntax.css',
|
||||
'uri' => '/res/cb3b9dc0/rsrc/css/core/syntax.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -2787,7 +2870,7 @@ celerity_register_resource_map(array(
|
|||
), array(
|
||||
'packages' =>
|
||||
array(
|
||||
'8b65e80d' =>
|
||||
'04e1ab3e' =>
|
||||
array(
|
||||
'name' => 'core.pkg.css',
|
||||
'symbols' =>
|
||||
|
@ -2816,7 +2899,7 @@ celerity_register_resource_map(array(
|
|||
21 => 'phabricator-flag-css',
|
||||
22 => 'aphront-error-view-css',
|
||||
),
|
||||
'uri' => '/res/pkg/8b65e80d/core.pkg.css',
|
||||
'uri' => '/res/pkg/04e1ab3e/core.pkg.css',
|
||||
'type' => 'css',
|
||||
),
|
||||
'971b021e' =>
|
||||
|
@ -2867,7 +2950,7 @@ celerity_register_resource_map(array(
|
|||
'uri' => '/res/pkg/96bc37d6/differential.pkg.css',
|
||||
'type' => 'css',
|
||||
),
|
||||
'ace0431a' =>
|
||||
93479628 =>
|
||||
array(
|
||||
'name' => 'differential.pkg.js',
|
||||
'symbols' =>
|
||||
|
@ -2891,7 +2974,7 @@ celerity_register_resource_map(array(
|
|||
16 => 'javelin-behavior-differential-dropdown-menus',
|
||||
17 => 'javelin-behavior-buoyant',
|
||||
),
|
||||
'uri' => '/res/pkg/ace0431a/differential.pkg.js',
|
||||
'uri' => '/res/pkg/93479628/differential.pkg.js',
|
||||
'type' => 'js',
|
||||
),
|
||||
'c8ce2d88' =>
|
||||
|
@ -2983,23 +3066,23 @@ celerity_register_resource_map(array(
|
|||
'reverse' =>
|
||||
array(
|
||||
'aphront-attached-file-view-css' => '7839ae2d',
|
||||
'aphront-crumbs-view-css' => '8b65e80d',
|
||||
'aphront-dialog-view-css' => '8b65e80d',
|
||||
'aphront-error-view-css' => '8b65e80d',
|
||||
'aphront-form-view-css' => '8b65e80d',
|
||||
'aphront-crumbs-view-css' => '04e1ab3e',
|
||||
'aphront-dialog-view-css' => '04e1ab3e',
|
||||
'aphront-error-view-css' => '04e1ab3e',
|
||||
'aphront-form-view-css' => '04e1ab3e',
|
||||
'aphront-headsup-action-list-view-css' => '96bc37d6',
|
||||
'aphront-headsup-view-css' => '8b65e80d',
|
||||
'aphront-list-filter-view-css' => '8b65e80d',
|
||||
'aphront-pager-view-css' => '8b65e80d',
|
||||
'aphront-panel-view-css' => '8b65e80d',
|
||||
'aphront-side-nav-view-css' => '8b65e80d',
|
||||
'aphront-table-view-css' => '8b65e80d',
|
||||
'aphront-tokenizer-control-css' => '8b65e80d',
|
||||
'aphront-tooltip-css' => '8b65e80d',
|
||||
'aphront-typeahead-control-css' => '8b65e80d',
|
||||
'aphront-headsup-view-css' => '04e1ab3e',
|
||||
'aphront-list-filter-view-css' => '04e1ab3e',
|
||||
'aphront-pager-view-css' => '04e1ab3e',
|
||||
'aphront-panel-view-css' => '04e1ab3e',
|
||||
'aphront-side-nav-view-css' => '04e1ab3e',
|
||||
'aphront-table-view-css' => '04e1ab3e',
|
||||
'aphront-tokenizer-control-css' => '04e1ab3e',
|
||||
'aphront-tooltip-css' => '04e1ab3e',
|
||||
'aphront-typeahead-control-css' => '04e1ab3e',
|
||||
'differential-changeset-view-css' => '96bc37d6',
|
||||
'differential-core-view-css' => '96bc37d6',
|
||||
'differential-inline-comment-editor' => 'ace0431a',
|
||||
'differential-inline-comment-editor' => '93479628',
|
||||
'differential-local-commits-view-css' => '96bc37d6',
|
||||
'differential-results-table-css' => '96bc37d6',
|
||||
'differential-revision-add-comment-css' => '96bc37d6',
|
||||
|
@ -3012,21 +3095,21 @@ celerity_register_resource_map(array(
|
|||
'inline-comment-summary-css' => '96bc37d6',
|
||||
'javelin-behavior' => '6fb20113',
|
||||
'javelin-behavior-aphront-basic-tokenizer' => '97f65640',
|
||||
'javelin-behavior-aphront-drag-and-drop' => 'ace0431a',
|
||||
'javelin-behavior-aphront-drag-and-drop-textarea' => 'ace0431a',
|
||||
'javelin-behavior-aphront-drag-and-drop' => '93479628',
|
||||
'javelin-behavior-aphront-drag-and-drop-textarea' => '93479628',
|
||||
'javelin-behavior-aphront-form-disable-on-submit' => '971b021e',
|
||||
'javelin-behavior-audit-preview' => '5e68be89',
|
||||
'javelin-behavior-buoyant' => 'ace0431a',
|
||||
'javelin-behavior-differential-accept-with-errors' => 'ace0431a',
|
||||
'javelin-behavior-differential-add-reviewers-and-ccs' => 'ace0431a',
|
||||
'javelin-behavior-differential-comment-jump' => 'ace0431a',
|
||||
'javelin-behavior-differential-diff-radios' => 'ace0431a',
|
||||
'javelin-behavior-differential-dropdown-menus' => 'ace0431a',
|
||||
'javelin-behavior-differential-edit-inline-comments' => 'ace0431a',
|
||||
'javelin-behavior-differential-feedback-preview' => 'ace0431a',
|
||||
'javelin-behavior-differential-keyboard-navigation' => 'ace0431a',
|
||||
'javelin-behavior-differential-populate' => 'ace0431a',
|
||||
'javelin-behavior-differential-show-more' => 'ace0431a',
|
||||
'javelin-behavior-buoyant' => '93479628',
|
||||
'javelin-behavior-differential-accept-with-errors' => '93479628',
|
||||
'javelin-behavior-differential-add-reviewers-and-ccs' => '93479628',
|
||||
'javelin-behavior-differential-comment-jump' => '93479628',
|
||||
'javelin-behavior-differential-diff-radios' => '93479628',
|
||||
'javelin-behavior-differential-dropdown-menus' => '93479628',
|
||||
'javelin-behavior-differential-edit-inline-comments' => '93479628',
|
||||
'javelin-behavior-differential-feedback-preview' => '93479628',
|
||||
'javelin-behavior-differential-keyboard-navigation' => '93479628',
|
||||
'javelin-behavior-differential-populate' => '93479628',
|
||||
'javelin-behavior-differential-show-more' => '93479628',
|
||||
'javelin-behavior-diffusion-commit-graph' => '5e68be89',
|
||||
'javelin-behavior-diffusion-pull-lastmodified' => '5e68be89',
|
||||
'javelin-behavior-maniphest-batch-selector' => '7707de41',
|
||||
|
@ -3036,12 +3119,12 @@ celerity_register_resource_map(array(
|
|||
'javelin-behavior-maniphest-transaction-preview' => '7707de41',
|
||||
'javelin-behavior-phabricator-autofocus' => '971b021e',
|
||||
'javelin-behavior-phabricator-keyboard-shortcuts' => '971b021e',
|
||||
'javelin-behavior-phabricator-object-selector' => 'ace0431a',
|
||||
'javelin-behavior-phabricator-object-selector' => '93479628',
|
||||
'javelin-behavior-phabricator-oncopy' => '971b021e',
|
||||
'javelin-behavior-phabricator-tooltips' => '971b021e',
|
||||
'javelin-behavior-phabricator-watch-anchor' => '971b021e',
|
||||
'javelin-behavior-refresh-csrf' => '971b021e',
|
||||
'javelin-behavior-repository-crossreference' => 'ace0431a',
|
||||
'javelin-behavior-repository-crossreference' => '93479628',
|
||||
'javelin-behavior-workflow' => '971b021e',
|
||||
'javelin-dom' => '6fb20113',
|
||||
'javelin-event' => '6fb20113',
|
||||
|
@ -3062,15 +3145,15 @@ celerity_register_resource_map(array(
|
|||
'javelin-workflow' => '971b021e',
|
||||
'maniphest-task-summary-css' => '7839ae2d',
|
||||
'maniphest-transaction-detail-css' => '7839ae2d',
|
||||
'phabricator-app-buttons-css' => '8b65e80d',
|
||||
'phabricator-app-buttons-css' => '04e1ab3e',
|
||||
'phabricator-content-source-view-css' => '96bc37d6',
|
||||
'phabricator-core-buttons-css' => '8b65e80d',
|
||||
'phabricator-core-css' => '8b65e80d',
|
||||
'phabricator-directory-css' => '8b65e80d',
|
||||
'phabricator-drag-and-drop-file-upload' => 'ace0431a',
|
||||
'phabricator-core-buttons-css' => '04e1ab3e',
|
||||
'phabricator-core-css' => '04e1ab3e',
|
||||
'phabricator-directory-css' => '04e1ab3e',
|
||||
'phabricator-drag-and-drop-file-upload' => '93479628',
|
||||
'phabricator-dropdown-menu' => '971b021e',
|
||||
'phabricator-flag-css' => '8b65e80d',
|
||||
'phabricator-jump-nav' => '8b65e80d',
|
||||
'phabricator-flag-css' => '04e1ab3e',
|
||||
'phabricator-jump-nav' => '04e1ab3e',
|
||||
'phabricator-keyboard-shortcut' => '971b021e',
|
||||
'phabricator-keyboard-shortcut-manager' => '971b021e',
|
||||
'phabricator-menu-item' => '971b021e',
|
||||
|
@ -3078,11 +3161,11 @@ celerity_register_resource_map(array(
|
|||
'phabricator-paste-file-upload' => '971b021e',
|
||||
'phabricator-prefab' => '971b021e',
|
||||
'phabricator-project-tag-css' => '7839ae2d',
|
||||
'phabricator-remarkup-css' => '8b65e80d',
|
||||
'phabricator-shaped-request' => 'ace0431a',
|
||||
'phabricator-standard-page-view' => '8b65e80d',
|
||||
'phabricator-remarkup-css' => '04e1ab3e',
|
||||
'phabricator-shaped-request' => '93479628',
|
||||
'phabricator-standard-page-view' => '04e1ab3e',
|
||||
'phabricator-tooltip' => '971b021e',
|
||||
'phabricator-transaction-view-css' => '8b65e80d',
|
||||
'syntax-highlighting-css' => '8b65e80d',
|
||||
'phabricator-transaction-view-css' => '04e1ab3e',
|
||||
'syntax-highlighting-css' => '04e1ab3e',
|
||||
),
|
||||
));
|
||||
|
|
|
@ -554,6 +554,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationManiphest' => 'applications/maniphest/application/PhabricatorApplicationManiphest.php',
|
||||
'PhabricatorApplicationPeople' => 'applications/people/application/PhabricatorApplicationPeople.php',
|
||||
'PhabricatorApplicationPhriction' => 'applications/phriction/application/PhabricatorApplicationPhriction.php',
|
||||
'PhabricatorApplicationPonder' => 'applications/ponder/application/PhabricatorApplicationPonder.php',
|
||||
'PhabricatorApplicationProject' => 'applications/project/application/PhabricatorApplicationProject.php',
|
||||
'PhabricatorApplicationSettings' => 'applications/people/application/PhabricatorApplicationSettings.php',
|
||||
'PhabricatorApplicationStatusView' => 'applications/meta/view/PhabricatorApplicationStatusView.php',
|
||||
|
@ -990,6 +991,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSearchIndexController' => 'applications/search/controller/PhabricatorSearchIndexController.php',
|
||||
'PhabricatorSearchManiphestIndexer' => 'applications/search/index/indexer/PhabricatorSearchManiphestIndexer.php',
|
||||
'PhabricatorSearchPhrictionIndexer' => 'applications/search/index/indexer/PhabricatorSearchPhrictionIndexer.php',
|
||||
'PhabricatorSearchPonderIndexer' => 'applications/ponder/search/PhabricatorSearchPonderIndexer.php',
|
||||
'PhabricatorSearchQuery' => 'applications/search/storage/PhabricatorSearchQuery.php',
|
||||
'PhabricatorSearchRelationship' => 'applications/search/constants/PhabricatorSearchRelationship.php',
|
||||
'PhabricatorSearchResultView' => 'applications/search/view/PhabricatorSearchResultView.php',
|
||||
|
@ -1137,6 +1139,34 @@ phutil_register_library_map(array(
|
|||
'PhrictionEditController' => 'applications/phriction/controller/PhrictionEditController.php',
|
||||
'PhrictionHistoryController' => 'applications/phriction/controller/PhrictionHistoryController.php',
|
||||
'PhrictionListController' => 'applications/phriction/controller/PhrictionListController.php',
|
||||
'PonderAddAnswerView' => 'applications/ponder/view/PonderAddAnswerView.php',
|
||||
'PonderAnswer' => 'applications/ponder/storage/PonderAnswer.php',
|
||||
'PonderAnswerEditor' => 'applications/ponder/editor/PonderAnswerEditor.php',
|
||||
'PonderAnswerListView' => 'applications/ponder/view/PonderAnswerListView.php',
|
||||
'PonderAnswerPreviewController' => 'applications/ponder/controller/PonderAnswerPreviewController.php',
|
||||
'PonderAnswerQuery' => 'applications/ponder/query/PonderAnswerQuery.php',
|
||||
'PonderAnswerSaveController' => 'applications/ponder/controller/PonderAnswerSaveController.php',
|
||||
'PonderAnswerSummaryView' => 'applications/ponder/view/PonderAnswerSummaryView.php',
|
||||
'PonderAnswerViewController' => 'applications/ponder/controller/PonderAnswerViewController.php',
|
||||
'PonderCommentBodyView' => 'applications/ponder/view/PonderCommentBodyView.php',
|
||||
'PonderConstants' => 'applications/ponder/PonderConstants.php',
|
||||
'PonderController' => 'applications/ponder/controller/PonderController.php',
|
||||
'PonderDAO' => 'applications/ponder/storage/PonderDAO.php',
|
||||
'PonderFeedController' => 'applications/ponder/controller/PonderFeedController.php',
|
||||
'PonderQuestion' => 'applications/ponder/storage/PonderQuestion.php',
|
||||
'PonderQuestionAskController' => 'applications/ponder/controller/PonderQuestionAskController.php',
|
||||
'PonderQuestionDetailView' => 'applications/ponder/view/PonderQuestionDetailView.php',
|
||||
'PonderQuestionFeedView' => 'applications/ponder/view/PonderQuestionFeedView.php',
|
||||
'PonderQuestionPreviewController' => 'applications/ponder/controller/PonderQuestionPreviewController.php',
|
||||
'PonderQuestionQuery' => 'applications/ponder/query/PonderQuestionQuery.php',
|
||||
'PonderQuestionSummaryView' => 'applications/ponder/view/PonderQuestionSummaryView.php',
|
||||
'PonderQuestionViewController' => 'applications/ponder/controller/PonderQuestionViewController.php',
|
||||
'PonderRuleQuestion' => 'infrastructure/markup/rule/PonderRuleQuestion.php',
|
||||
'PonderUserProfileView' => 'applications/ponder/view/PonderUserProfileView.php',
|
||||
'PonderVotableInterface' => 'applications/ponder/storage/PonderVotableInterface.php',
|
||||
'PonderVotableView' => 'applications/ponder/view/PonderVotableView.php',
|
||||
'PonderVoteEditor' => 'applications/ponder/editor/PonderVoteEditor.php',
|
||||
'PonderVoteSaveController' => 'applications/ponder/controller/PonderVoteSaveController.php',
|
||||
'QueryFormattingTestCase' => 'infrastructure/storage/__tests__/QueryFormattingTestCase.php',
|
||||
),
|
||||
'function' =>
|
||||
|
@ -1641,6 +1671,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationManiphest' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationPeople' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationPhriction' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationPonder' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationProject' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationSettings' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationStatusView' => 'AphrontView',
|
||||
|
@ -2029,6 +2060,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSearchIndexController' => 'PhabricatorSearchBaseController',
|
||||
'PhabricatorSearchManiphestIndexer' => 'PhabricatorSearchDocumentIndexer',
|
||||
'PhabricatorSearchPhrictionIndexer' => 'PhabricatorSearchDocumentIndexer',
|
||||
'PhabricatorSearchPonderIndexer' => 'PhabricatorSearchDocumentIndexer',
|
||||
'PhabricatorSearchQuery' => 'PhabricatorSearchDAO',
|
||||
'PhabricatorSearchResultView' => 'AphrontView',
|
||||
'PhabricatorSearchSelectController' => 'PhabricatorSearchBaseController',
|
||||
|
@ -2169,6 +2201,40 @@ phutil_register_library_map(array(
|
|||
'PhrictionEditController' => 'PhrictionController',
|
||||
'PhrictionHistoryController' => 'PhrictionController',
|
||||
'PhrictionListController' => 'PhrictionController',
|
||||
'PonderAddAnswerView' => 'AphrontView',
|
||||
'PonderAnswer' =>
|
||||
array(
|
||||
0 => 'PonderDAO',
|
||||
1 => 'PhabricatorMarkupInterface',
|
||||
2 => 'PonderVotableInterface',
|
||||
),
|
||||
'PonderAnswerListView' => 'AphrontView',
|
||||
'PonderAnswerPreviewController' => 'PonderController',
|
||||
'PonderAnswerQuery' => 'PhabricatorOffsetPagedQuery',
|
||||
'PonderAnswerSaveController' => 'PonderController',
|
||||
'PonderAnswerSummaryView' => 'AphrontView',
|
||||
'PonderAnswerViewController' => 'PonderController',
|
||||
'PonderCommentBodyView' => 'AphrontView',
|
||||
'PonderController' => 'PhabricatorController',
|
||||
'PonderDAO' => 'PhabricatorLiskDAO',
|
||||
'PonderFeedController' => 'PonderController',
|
||||
'PonderQuestion' =>
|
||||
array(
|
||||
0 => 'PonderDAO',
|
||||
1 => 'PhabricatorMarkupInterface',
|
||||
2 => 'PonderVotableInterface',
|
||||
),
|
||||
'PonderQuestionAskController' => 'PonderController',
|
||||
'PonderQuestionDetailView' => 'AphrontView',
|
||||
'PonderQuestionFeedView' => 'AphrontView',
|
||||
'PonderQuestionPreviewController' => 'PonderController',
|
||||
'PonderQuestionQuery' => 'PhabricatorOffsetPagedQuery',
|
||||
'PonderQuestionSummaryView' => 'AphrontView',
|
||||
'PonderQuestionViewController' => 'PonderController',
|
||||
'PonderRuleQuestion' => 'PhabricatorRemarkupRuleObjectName',
|
||||
'PonderUserProfileView' => 'AphrontView',
|
||||
'PonderVotableView' => 'AphrontView',
|
||||
'PonderVoteSaveController' => 'PonderController',
|
||||
'QueryFormattingTestCase' => 'PhabricatorTestCase',
|
||||
),
|
||||
));
|
||||
|
|
|
@ -320,7 +320,6 @@ class AphrontDefaultApplicationConfiguration
|
|||
|
||||
'/emailverify/(?P<code>[^/]+)/' =>
|
||||
'PhabricatorEmailVerificationController',
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -42,4 +42,6 @@ final class PhabricatorPHIDConstants {
|
|||
const PHID_TYPE_POST = 'POST';
|
||||
const PHID_TYPE_TOBJ = 'TOBJ';
|
||||
const PHID_TYPE_BLOG = 'BLOG';
|
||||
const PHID_TYPE_QUES = 'QUES';
|
||||
const PHID_TYPE_ANSW = 'ANSW';
|
||||
}
|
||||
|
|
|
@ -439,6 +439,27 @@ final class PhabricatorObjectHandleData {
|
|||
$handles[$phid] = $handle;
|
||||
}
|
||||
break;
|
||||
case PhabricatorPHIDConstants::PHID_TYPE_QUES:
|
||||
$questions = id(new PonderQuestionQuery())
|
||||
->withPHIDs($phids)
|
||||
->execute();
|
||||
$questions = mpull($questions, 'getPHID');
|
||||
|
||||
foreach ($phids as $phid) {
|
||||
$handle = new PhabricatorObjectHandle();
|
||||
$handle->setPHID($phid);
|
||||
$handle->setType($type);
|
||||
if (empty($questions[$phid])) {
|
||||
$handle->setName('Unknown Ponder Question');
|
||||
} else {
|
||||
$question = $questions[$phid];
|
||||
$handle->setName(phutil_utf8_shorten($question->getTitle(), 60));
|
||||
$handle->setURI(new PhutilURI('Q' . $question->getID()));
|
||||
$handle->setComplete(true);
|
||||
}
|
||||
$handles[$phid] = $handle;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$loader = null;
|
||||
if (isset($external_loaders[$type])) {
|
||||
|
|
26
src/applications/ponder/PonderConstants.php
Normal file
26
src/applications/ponder/PonderConstants.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?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 PonderConstants {
|
||||
const UP_VOTE = 1;
|
||||
const NONE_VOTE = 0;
|
||||
const DOWN_VOTE = -1;
|
||||
|
||||
const ANSWERED_LITERAL = "answered";
|
||||
const ASKED_LITERAL = "asked";
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
<?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 PhabricatorApplicationPonder extends PhabricatorApplication {
|
||||
|
||||
public function getBaseURI() {
|
||||
return '/ponder/';
|
||||
}
|
||||
|
||||
public function getShortDescription() {
|
||||
return 'Find Answers';
|
||||
}
|
||||
|
||||
public function getIconURI() {
|
||||
return celerity_get_resource_uri('/rsrc/image/app/app_ponder.png');
|
||||
}
|
||||
|
||||
public function getFactObjectsForAnalysis() {
|
||||
return array(
|
||||
new PonderQuestion(),
|
||||
);
|
||||
}
|
||||
|
||||
public function loadStatus(PhabricatorUser $user) {
|
||||
// replace with "x new unanswered questions" or some such
|
||||
$status = array();
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
public function getroutes() {
|
||||
return array(
|
||||
'/Q(?P<id>\d+)' => 'PonderQuestionViewController',
|
||||
'/ponder/' => array(
|
||||
'(?P<page>feed/)?' => 'PonderFeedController',
|
||||
'(?P<page>profile)/' => 'PonderFeedController',
|
||||
'answer/add/' => 'PonderAnswerSaveController',
|
||||
'answer/preview/' => 'PonderAnswerPreviewController',
|
||||
'question/ask/' => 'PonderQuestionAskController',
|
||||
'question/preview/' => 'PonderQuestionPreviewController',
|
||||
'(?P<kind>question)/vote/' => 'PonderVoteSaveController',
|
||||
'(?P<kind>answer)/vote/' => 'PonderVoteSaveController'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<?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 PonderAnswerPreviewController
|
||||
extends PonderController {
|
||||
|
||||
public function processRequest() {
|
||||
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$question_id = $request->getInt('question_id');
|
||||
|
||||
$question = PonderQuestionQuery::loadSingle($user, $question_id);
|
||||
if (!$question) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$author_phid = $user->getPHID();
|
||||
$object_phids = array($author_phid);
|
||||
$handles = id(new PhabricatorObjectHandleData($object_phids))
|
||||
->loadHandles();
|
||||
|
||||
$answer = new PonderAnswer();
|
||||
$answer->setContent($request->getStr('content'));
|
||||
$answer->setAuthorPHID($author_phid);
|
||||
|
||||
$view = new PonderCommentBodyView();
|
||||
$view
|
||||
->setQuestion($question)
|
||||
->setTarget($answer)
|
||||
->setPreview(true)
|
||||
->setUser($user)
|
||||
->setHandles($handles)
|
||||
->setAction(PonderConstants::ANSWERED_LITERAL);
|
||||
|
||||
return id(new AphrontAjaxResponse())
|
||||
->setContent($view->render());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
<?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 PonderAnswerSaveController extends PonderController {
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
if (!$request->isFormPost()) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
$user = $request->getUser();
|
||||
$question_id = $request->getInt('question_id');
|
||||
$question = PonderQuestionQuery::loadSingle($user, $question_id);
|
||||
|
||||
if (!$question) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$answer = $request->getStr('answer');
|
||||
|
||||
$content_source = PhabricatorContentSource::newForSource(
|
||||
PhabricatorContentSource::SOURCE_WEB,
|
||||
array(
|
||||
'ip' => $request->getRemoteAddr(),
|
||||
));
|
||||
|
||||
$res = new PonderAnswer();
|
||||
$res
|
||||
->setContent($answer)
|
||||
->setAuthorPHID($user->getPHID())
|
||||
->setVoteCount(0)
|
||||
->setQuestionID($question_id)
|
||||
->setContentSource($content_source);
|
||||
|
||||
id(new PonderAnswerEditor())
|
||||
->setQuestion($question)
|
||||
->setAnswer($res)
|
||||
->saveAnswer();
|
||||
|
||||
PhabricatorSearchPonderIndexer::indexQuestion($question);
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI(id(new PhutilURI('/Q'. $question->getID()))
|
||||
->setFragment('A'.$res->getID()));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?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 PonderAnswerViewController extends PonderController {
|
||||
|
||||
private $answerID;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->answerID = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$answer = id(new PonderAnswer())->load($this->answerID);
|
||||
|
||||
if (!$answer) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$question_id = $answer->getQuestionID();
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/Q'.$question_id . '#A' . $answer->getID());
|
||||
}
|
||||
|
||||
}
|
35
src/applications/ponder/controller/PonderController.php
Normal file
35
src/applications/ponder/controller/PonderController.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?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 PonderController extends PhabricatorController {
|
||||
|
||||
public function buildStandardPageResponse($view, array $data) {
|
||||
|
||||
$page = $this->buildStandardPageView();
|
||||
$page->setApplicationName('Ponder!');
|
||||
$page->setBaseURI('/ponder/');
|
||||
$page->setTitle(idx($data, 'title'));
|
||||
$page->setGlyph("\xE2\x97\xB3");
|
||||
$page->appendChild($view);
|
||||
$page->setSearchDefaultScope(PhabricatorSearchScope::SCOPE_QUESTIONS);
|
||||
|
||||
$response = new AphrontWebpageResponse();
|
||||
return $response->setContent($page->render());
|
||||
}
|
||||
|
||||
}
|
143
src/applications/ponder/controller/PonderFeedController.php
Normal file
143
src/applications/ponder/controller/PonderFeedController.php
Normal file
|
@ -0,0 +1,143 @@
|
|||
<?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 PonderFeedController extends PonderController {
|
||||
private $page;
|
||||
private $feedOffset;
|
||||
private $questionOffset;
|
||||
private $answerOffset;
|
||||
|
||||
const PAGE_FEED = "feed";
|
||||
const PAGE_PROFILE = "profile";
|
||||
|
||||
const FEED_PAGE_SIZE = 20;
|
||||
const PROFILE_QUESTION_PAGE_SIZE = 10;
|
||||
const PROFILE_ANSWER_PAGE_SIZE = 10;
|
||||
|
||||
static $pages = array(
|
||||
self::PAGE_FEED => "Popular Questions",
|
||||
self::PAGE_PROFILE => "User Profile"
|
||||
);
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
if (isset($data['page'])) {
|
||||
$this->page = $data['page'];
|
||||
}
|
||||
|
||||
if (!isset(self::$pages[$this->page])) {
|
||||
$this->page = self::PAGE_FEED;
|
||||
}
|
||||
|
||||
$this->feedOffset = 0;
|
||||
if (isset($data['feedoffset'])) {
|
||||
$this->feedOffset = $data['feedoffset'];
|
||||
}
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$this->feedOffset = $request->getInt('off');
|
||||
$this->questionOffset = $request->getInt('qoff');
|
||||
$this->answerOffset = $request->getInt('aoff');
|
||||
|
||||
$side_nav = new AphrontSideNavView();
|
||||
foreach (self::$pages as $pagename => $pagetitle) {
|
||||
$class = "";
|
||||
if ($pagename == $this->page) {
|
||||
$class = 'aphront-side-nav-selected';
|
||||
}
|
||||
|
||||
$linky = phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/ponder/'.$pagename .'/',
|
||||
'class' => $class
|
||||
),
|
||||
phutil_escape_html($pagetitle)
|
||||
);
|
||||
|
||||
$side_nav->addNavItem($linky);
|
||||
}
|
||||
|
||||
switch ($this->page) {
|
||||
case self::PAGE_FEED:
|
||||
$data = PonderQuestionQuery::loadHottest(
|
||||
$user,
|
||||
$this->feedOffset,
|
||||
self::FEED_PAGE_SIZE + 1);
|
||||
|
||||
$phids = array();
|
||||
foreach ($data as $question) {
|
||||
$phids[] = $question->getAuthorPHID();
|
||||
}
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))
|
||||
->loadHandles();
|
||||
|
||||
$side_nav->appendChild(
|
||||
id(new PonderQuestionFeedView())
|
||||
->setUser($user)
|
||||
->setData($data)
|
||||
->setHandles($handles)
|
||||
->setOffset($this->feedOffset)
|
||||
->setPageSize(self::FEED_PAGE_SIZE)
|
||||
->setURI(new PhutilURI("/ponder/feed/"), "off")
|
||||
);
|
||||
break;
|
||||
case self::PAGE_PROFILE:
|
||||
$questions = PonderQuestionQuery::loadByAuthor(
|
||||
$user,
|
||||
$user->getPHID(),
|
||||
$this->questionOffset,
|
||||
self::PROFILE_QUESTION_PAGE_SIZE + 1
|
||||
);
|
||||
|
||||
$answers = PonderAnswerQuery::loadByAuthorWithQuestions(
|
||||
$user,
|
||||
$user->getPHID(),
|
||||
$this->answerOffset,
|
||||
self::PROFILE_ANSWER_PAGE_SIZE + 1
|
||||
);
|
||||
|
||||
$phids = array($user->getPHID());
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))
|
||||
->loadHandles();
|
||||
|
||||
$side_nav->appendChild(
|
||||
id(new PonderUserProfileView())
|
||||
->setUser($user)
|
||||
->setQuestions($questions)
|
||||
->setAnswers($answers)
|
||||
->setHandles($handles)
|
||||
->setQuestionOffset($this->questionOffset)
|
||||
->setAnswerOffset($this->answerOffset)
|
||||
->setPageSize(self::PROFILE_QUESTION_PAGE_SIZE)
|
||||
->setURI(new PhutilURI("/ponder/profile/"), "qoff", "aoff")
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
$side_nav,
|
||||
array(
|
||||
'title' => self::$pages[$this->page]
|
||||
));
|
||||
}
|
||||
|
||||
}
|
|
@ -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.
|
||||
*/
|
||||
|
||||
final class PonderQuestionAskController extends PonderController {
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
return $this->handlePost();
|
||||
}
|
||||
|
||||
return $this->showForm();
|
||||
}
|
||||
|
||||
private function handlePost() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$errors = array();
|
||||
$title = $request->getStr('title');
|
||||
$content = $request->getStr('content');
|
||||
|
||||
// form validation
|
||||
if (phutil_utf8_strlen($title) < 1 || phutil_utf8_strlen($title) > 255) {
|
||||
$errors[] = "Please enter a title (1-255 characters)";
|
||||
}
|
||||
|
||||
if ($errors) {
|
||||
return $this->showForm($errors, $title, $content);
|
||||
}
|
||||
|
||||
// no validation errors -> save it
|
||||
|
||||
$content_source = PhabricatorContentSource::newForSource(
|
||||
PhabricatorContentSource::SOURCE_WEB,
|
||||
array(
|
||||
'ip' => $request->getRemoteAddr(),
|
||||
));
|
||||
|
||||
$question = id(new PonderQuestion())
|
||||
->setTitle($title)
|
||||
->setContent($content)
|
||||
->setAuthorPHID($user->getPHID())
|
||||
->setContentSource($content_source)
|
||||
->setVoteCount(0)
|
||||
->setAnswerCount(0)
|
||||
->setHeat(0.0)
|
||||
->save();
|
||||
|
||||
PhabricatorSearchPonderIndexer::indexQuestion($question);
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/Q'.$question->getID());
|
||||
}
|
||||
|
||||
private function showForm(
|
||||
$errors = null,
|
||||
$title = "",
|
||||
$content = "",
|
||||
$id = null) {
|
||||
|
||||
require_celerity_resource('ponder-core-view-css');
|
||||
require_celerity_resource('phabricator-remarkup-css');
|
||||
require_celerity_resource('ponder-post-css');
|
||||
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$error_view = null;
|
||||
|
||||
if ($errors) {
|
||||
$error_view = id(new AphrontErrorView())
|
||||
->setTitle('Form Errors')
|
||||
->setErrors($errors);
|
||||
}
|
||||
|
||||
$form = new AphrontFormView();
|
||||
$form->setUser($user);
|
||||
$form->setAction('/ponder/question/ask/');
|
||||
$form
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel('Title')
|
||||
->setName('title')
|
||||
->setValue($title))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextAreaControl())
|
||||
->setName('content')
|
||||
->setID('content')
|
||||
->setValue($content)
|
||||
->setLabel("Question")
|
||||
->setCaption(phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => PhabricatorEnv::getDoclink(
|
||||
'article/Remarkup_Reference.html'),
|
||||
'tabindex' => '-1',
|
||||
'target' => '_blank',
|
||||
),
|
||||
"Formatting Reference")))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue('Ask Away!'));
|
||||
|
||||
$panel = id(new AphrontPanelView())
|
||||
->addClass("ponder-panel")
|
||||
->setHeader("Your Question:")
|
||||
->appendChild($error_view)
|
||||
->appendChild($form);
|
||||
|
||||
$panel->appendChild(
|
||||
'<div class="aphront-panel-flush">'.
|
||||
'<div id="question-preview">'.
|
||||
'<span class="aphront-panel-preview-loading-text">'.
|
||||
'Loading question preview...'.
|
||||
'</span>'.
|
||||
'</div>'.
|
||||
'</div>'
|
||||
);
|
||||
|
||||
Javelin::initBehavior(
|
||||
'ponder-feedback-preview',
|
||||
array(
|
||||
'uri' => '/ponder/question/preview/',
|
||||
'content' => 'content',
|
||||
'preview' => 'question-preview',
|
||||
'question_id' => null
|
||||
));
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
array($panel),
|
||||
array('title' => 'Ask a Question')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
<?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 PonderQuestionPreviewController
|
||||
extends PonderController {
|
||||
|
||||
const VERB_ASKED = "asked";
|
||||
|
||||
public function processRequest() {
|
||||
|
||||
$request = $this->getRequest();
|
||||
|
||||
$user = $request->getUser();
|
||||
$author_phid = $user->getPHID();
|
||||
|
||||
$object_phids = array($author_phid);
|
||||
$handles = id(new PhabricatorObjectHandleData($object_phids))
|
||||
->loadHandles();
|
||||
|
||||
$question = new PonderQuestion();
|
||||
$question->setContent($request->getStr('content'));
|
||||
$question->setAuthorPHID($author_phid);
|
||||
|
||||
$view = new PonderCommentBodyView();
|
||||
$view
|
||||
->setQuestion($question)
|
||||
->setTarget($question)
|
||||
->setPreview(true)
|
||||
->setUser($user)
|
||||
->setHandles($handles)
|
||||
->setAction(self::VERB_ASKED);
|
||||
|
||||
return id(new AphrontAjaxResponse())
|
||||
->setContent($view->render());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<?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 PonderQuestionViewController extends PonderController {
|
||||
|
||||
private $questionID;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->questionID = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$question = PonderQuestionQuery::loadSingle($user, $this->questionID);
|
||||
if (!$question) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$question->attachRelated($user->getPHID());
|
||||
$answers = $question->getAnswers();
|
||||
|
||||
$object_phids = array($user->getPHID(), $question->getAuthorPHID());
|
||||
foreach ($answers as $answer) {
|
||||
$object_phids[] = $answer->getAuthorPHID();
|
||||
}
|
||||
|
||||
$handles = id(new PhabricatorObjectHandleData($object_phids))
|
||||
->loadHandles();
|
||||
|
||||
$detail_panel = new PonderQuestionDetailView();
|
||||
$detail_panel
|
||||
->setQuestion($question)
|
||||
->setUser($user)
|
||||
->setHandles($handles);
|
||||
|
||||
$responses_panel = new PonderAnswerListView();
|
||||
$responses_panel
|
||||
->setQuestion($question)
|
||||
->setHandles($handles)
|
||||
->setUser($user)
|
||||
->setAnswers($answers);
|
||||
|
||||
$answer_add_panel = new PonderAddAnswerView();
|
||||
$answer_add_panel
|
||||
->setQuestion($question)
|
||||
->setUser($user)
|
||||
->setActionURI("/ponder/answer/add/");
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
array(
|
||||
$detail_panel,
|
||||
$responses_panel,
|
||||
$answer_add_panel
|
||||
),
|
||||
array(
|
||||
'title' => 'Q'.$question->getID().' '.$question->getTitle()
|
||||
));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
<?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 PonderVoteSaveController extends PonderController {
|
||||
|
||||
private $kind;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->kind = $data['kind'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$newvote = $request->getInt("vote");
|
||||
$phid = $request->getStr("phid");
|
||||
|
||||
if (1 < $newvote || $newvote < -1) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
$target = null;
|
||||
|
||||
if ($this->kind == "question") {
|
||||
$target = PonderQuestionQuery::loadSingleByPHID($user, $phid);
|
||||
}
|
||||
else if ($this->kind == "answer") {
|
||||
$target = PonderAnswerQuery::loadSingleByPHID($user, $phid);
|
||||
}
|
||||
|
||||
if (!$target) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$editor = id(new PonderVoteEditor())
|
||||
->setVotable($target)
|
||||
->setUser($user)
|
||||
->setVote($newvote)
|
||||
->saveVote();
|
||||
|
||||
return id(new AphrontAjaxResponse())->setContent(".");
|
||||
}
|
||||
}
|
64
src/applications/ponder/editor/PonderAnswerEditor.php
Normal file
64
src/applications/ponder/editor/PonderAnswerEditor.php
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?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 PonderAnswerEditor {
|
||||
|
||||
private $question;
|
||||
private $answer;
|
||||
|
||||
public function setQuestion($question) {
|
||||
$this->question = $question;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setAnswer($answer) {
|
||||
$this->answer = $answer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function saveAnswer() {
|
||||
if (!$this->question) {
|
||||
throw new Exception("Must set question before saving vote");
|
||||
}
|
||||
if (!$this->answer) {
|
||||
throw new Exception("Must set answer before saving vote");
|
||||
}
|
||||
|
||||
$question = $this->question;
|
||||
$answer = $this->answer;
|
||||
$conn = $answer->establishConnection('w');
|
||||
$trans = $conn->openTransaction();
|
||||
$trans->beginReadLocking();
|
||||
|
||||
$question->reload();
|
||||
|
||||
queryfx($conn,
|
||||
'UPDATE %T as t
|
||||
SET t.`answerCount` = t.`answerCount` + 1
|
||||
WHERE t.`PHID` = %s',
|
||||
$question->getTableName(),
|
||||
$question->getPHID());
|
||||
|
||||
$answer->setQuestionID($question->getID());
|
||||
$answer->save();
|
||||
|
||||
$trans->endReadLocking();
|
||||
$trans->saveTransaction();
|
||||
}
|
||||
}
|
104
src/applications/ponder/editor/PonderVoteEditor.php
Normal file
104
src/applications/ponder/editor/PonderVoteEditor.php
Normal file
|
@ -0,0 +1,104 @@
|
|||
<?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 PonderVoteEditor {
|
||||
|
||||
private $answer;
|
||||
private $votable;
|
||||
private $anwer;
|
||||
private $user;
|
||||
private $vote;
|
||||
|
||||
public function setAnswer($answer) {
|
||||
$this->answer = $answer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setVotable($votable) {
|
||||
$this->votable = $votable;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUser($user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setVote($vote) {
|
||||
$this->vote = $vote;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function saveVote() {
|
||||
if (!$this->votable) {
|
||||
throw new Exception("Must set votable before saving vote");
|
||||
}
|
||||
if (!$this->user) {
|
||||
throw new Exception("Must set user before saving vote");
|
||||
}
|
||||
|
||||
$user = $this->user;
|
||||
$votable = $this->votable;
|
||||
$newvote = $this->vote;
|
||||
|
||||
// prepare vote add, or update if this user is amending an
|
||||
// earlier vote
|
||||
$editor = id(new PhabricatorEdgeEditor())
|
||||
->setUser($user)
|
||||
->addEdge(
|
||||
$user->getPHID(),
|
||||
$votable->getUserVoteEdgeType(),
|
||||
$votable->getVotablePHID(),
|
||||
array('data' => $newvote))
|
||||
->removeEdge(
|
||||
$user->getPHID(),
|
||||
$votable->getUserVoteEdgeType(),
|
||||
$votable->getVotablePHID());
|
||||
|
||||
$conn = $votable->establishConnection('w');
|
||||
$trans = $conn->openTransaction();
|
||||
$trans->beginReadLocking();
|
||||
|
||||
$votable->reload();
|
||||
$curvote = (int)PhabricatorEdgeQuery::loadSingleEdgeData(
|
||||
$user->getPHID(),
|
||||
$votable->getUserVoteEdgeType(),
|
||||
$votable->getVotablePHID());
|
||||
|
||||
if (!$curvote) {
|
||||
$curvote = PonderConstants::NONE_VOTE;
|
||||
}
|
||||
|
||||
// adjust votable's score by this much
|
||||
$delta = $newvote - $curvote;
|
||||
|
||||
queryfx($conn,
|
||||
'UPDATE %T as t
|
||||
SET t.`voteCount` = t.`voteCount` + %d
|
||||
WHERE t.`PHID` = %s',
|
||||
$votable->getTableName(),
|
||||
$delta,
|
||||
$votable->getVotablePHID());
|
||||
|
||||
$editor->save();
|
||||
|
||||
$trans->endReadLocking();
|
||||
$trans->saveTransaction();
|
||||
}
|
||||
}
|
161
src/applications/ponder/query/PonderAnswerQuery.php
Normal file
161
src/applications/ponder/query/PonderAnswerQuery.php
Normal file
|
@ -0,0 +1,161 @@
|
|||
<?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 PonderAnswerQuery extends PhabricatorOffsetPagedQuery {
|
||||
|
||||
private $id;
|
||||
private $phid;
|
||||
private $authorPHID;
|
||||
private $orderNewest;
|
||||
|
||||
public function withID($qid) {
|
||||
$this->id = $qid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withPHID($phid) {
|
||||
$this->phid = $phid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withAuthorPHID($phid) {
|
||||
$this->authorPHID = $phid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function orderByNewest($usethis) {
|
||||
$this->orderNewest = $usethis;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public static function loadByAuthorWithQuestions(
|
||||
$viewer,
|
||||
$phid,
|
||||
$offset,
|
||||
$count) {
|
||||
|
||||
if (!$viewer) {
|
||||
throw new Exception("Must set viewer when calling loadByAuthor...");
|
||||
}
|
||||
|
||||
$answers = id(new PonderAnswerQuery())
|
||||
->withAuthorPHID($phid)
|
||||
->orderByNewest(true)
|
||||
->setOffset($offset)
|
||||
->setLimit($count)
|
||||
->execute();
|
||||
|
||||
$answerset = new LiskDAOSet();
|
||||
foreach ($answers as $answer) {
|
||||
$answerset->addToSet($answer);
|
||||
}
|
||||
|
||||
foreach ($answers as $answer) {
|
||||
$question = $answer->loadOneRelative(
|
||||
new PonderQuestion(),
|
||||
'id',
|
||||
'getQuestionID');
|
||||
$answer->setQuestion($question);
|
||||
}
|
||||
|
||||
return $answers;
|
||||
}
|
||||
|
||||
public static function loadByAuthor($viewer, $author_phid, $offset, $count) {
|
||||
if (!$viewer) {
|
||||
throw new Exception("Must set viewer when calling loadByAuthor");
|
||||
}
|
||||
|
||||
return id(new PonderAnswerQuery())
|
||||
->withAuthorPHID($author_phid)
|
||||
->setOffset($offset)
|
||||
->setLimit($count)
|
||||
->orderByNewest(true)
|
||||
->execute();
|
||||
}
|
||||
|
||||
public static function loadSingle($viewer, $id) {
|
||||
if (!$viewer) {
|
||||
throw new Exception("Must set viewer when calling loadSingle");
|
||||
}
|
||||
return idx(id(new PonderAnswerQuery())
|
||||
->withID($id)
|
||||
->execute(), $id);
|
||||
}
|
||||
|
||||
public static function loadSingleByPHID($viewer, $phid) {
|
||||
if (!$viewer) {
|
||||
throw new Exception("Must set viewer when calling loadSingle");
|
||||
}
|
||||
|
||||
return array_shift(id(new PonderAnswerQuery())
|
||||
->withPHID($phid)
|
||||
->execute());
|
||||
}
|
||||
|
||||
private function buildWhereClause($conn_r) {
|
||||
$where = array();
|
||||
if ($this->id) {
|
||||
$where[] = qsprintf($conn_r, '(id = %d)', $this->id);
|
||||
}
|
||||
if ($this->phid) {
|
||||
$where[] = qsprintf($conn_r, '(phid = %s)', $this->phid);
|
||||
}
|
||||
if ($this->authorPHID) {
|
||||
$where[] = qsprintf($conn_r, '(authorPHID = %s)', $this->authorPHID);
|
||||
}
|
||||
|
||||
return $this->formatWhereClause($where);
|
||||
}
|
||||
|
||||
private function buildOrderByClause($conn_r) {
|
||||
$order = array();
|
||||
if ($this->orderNewest) {
|
||||
$order[] = qsprintf($conn_r, 'id DESC');
|
||||
}
|
||||
|
||||
if (count($order) == 0) {
|
||||
$order[] = qsprintf($conn_r, 'id ASC');
|
||||
}
|
||||
|
||||
return ($order ? 'ORDER BY ' . implode(', ', $order) : '');
|
||||
}
|
||||
|
||||
public function execute() {
|
||||
$answer = new PonderAnswer();
|
||||
$conn_r = $answer->establishConnection('r');
|
||||
|
||||
$select = qsprintf(
|
||||
$conn_r,
|
||||
'SELECT r.* FROM %T r',
|
||||
$answer->getTableName());
|
||||
|
||||
$where = $this->buildWhereClause($conn_r);
|
||||
$order_by = $this->buildOrderByClause($conn_r);
|
||||
$limit = $this->buildLimitClause($conn_r);
|
||||
|
||||
return $answer->loadAllFromArray(
|
||||
queryfx_all(
|
||||
$conn_r,
|
||||
'%Q %Q %Q %Q',
|
||||
$select,
|
||||
$where,
|
||||
$order_by,
|
||||
$limit));
|
||||
}
|
||||
}
|
157
src/applications/ponder/query/PonderQuestionQuery.php
Normal file
157
src/applications/ponder/query/PonderQuestionQuery.php
Normal file
|
@ -0,0 +1,157 @@
|
|||
<?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 PonderQuestionQuery extends PhabricatorOffsetPagedQuery {
|
||||
|
||||
private $id;
|
||||
private $phids;
|
||||
private $authorPHID;
|
||||
private $orderHottest;
|
||||
private $orderNewest;
|
||||
|
||||
public function withID($qid) {
|
||||
$this->id = $qid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withPHID($phid) {
|
||||
$this->phids = array($phid);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withPHIDs($phids) {
|
||||
$this->phids = $phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withAuthorPHID($phid) {
|
||||
$this->authorPHID = $phid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function orderByHottest($usethis) {
|
||||
$this->orderHottest = $usethis;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function orderByNewest($usethis) {
|
||||
$this->orderNewest = $usethis;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public static function loadHottest($viewer, $offset, $count) {
|
||||
if (!$viewer) {
|
||||
throw new Exception("Must set viewer when calling loadHottest");
|
||||
}
|
||||
|
||||
return id(new PonderQuestionQuery())
|
||||
->setOffset($offset)
|
||||
->setLimit($count)
|
||||
->orderByHottest(true)
|
||||
->execute();
|
||||
}
|
||||
|
||||
public static function loadByAuthor($viewer, $author_phid, $offset, $count) {
|
||||
if (!$viewer) {
|
||||
throw new Exception("Must set viewer when calling loadByAuthor");
|
||||
}
|
||||
|
||||
return id(new PonderQuestionQuery())
|
||||
->withAuthorPHID($author_phid)
|
||||
->setOffset($offset)
|
||||
->setLimit($count)
|
||||
->orderByNewest(true)
|
||||
->execute();
|
||||
}
|
||||
|
||||
public static function loadSingle($viewer, $id) {
|
||||
if (!$viewer) {
|
||||
throw new Exception("Must set viewer when calling loadSingle");
|
||||
}
|
||||
|
||||
return idx(id(new PonderQuestionQuery())
|
||||
->withID($id)
|
||||
->execute(), $id);
|
||||
}
|
||||
|
||||
public static function loadSingleByPHID($viewer, $phid) {
|
||||
if (!$viewer) {
|
||||
throw new Exception("Must set viewer when calling loadSingle");
|
||||
}
|
||||
|
||||
return array_shift(id(new PonderQuestionQuery())
|
||||
->withPHID($phid)
|
||||
->execute());
|
||||
}
|
||||
|
||||
private function buildWhereClause($conn_r) {
|
||||
$where = array();
|
||||
if ($this->id) {
|
||||
$where[] = qsprintf($conn_r, '(id = %d)', $this->id);
|
||||
}
|
||||
if ($this->phids) {
|
||||
$where[] = qsprintf($conn_r, '(phid in (%Ls))', $this->phids);
|
||||
}
|
||||
if ($this->authorPHID) {
|
||||
$where[] = qsprintf($conn_r, '(authorPHID = %s)', $this->authorPHID);
|
||||
}
|
||||
|
||||
return ($where ? 'WHERE ' . implode(' AND ', $where) : '');
|
||||
}
|
||||
|
||||
private function buildOrderByClause($conn_r) {
|
||||
$order = array();
|
||||
if ($this->orderHottest) {
|
||||
$order[] = qsprintf($conn_r, 'heat DESC');
|
||||
}
|
||||
if ($this->orderNewest) {
|
||||
$order[] = qsprintf($conn_r, 'id DESC');
|
||||
}
|
||||
|
||||
if (count($order) == 0) {
|
||||
$order[] = qsprintf($conn_r, 'id ASC');
|
||||
}
|
||||
|
||||
return ($order ? 'ORDER BY ' . implode(', ', $order) : '');
|
||||
}
|
||||
|
||||
public function execute() {
|
||||
$question = new PonderQuestion();
|
||||
$conn_r = $question->establishConnection('r');
|
||||
|
||||
$select = qsprintf(
|
||||
$conn_r,
|
||||
'SELECT r.* FROM %T r',
|
||||
$question->getTableName());
|
||||
|
||||
$where = $this->buildWhereClause($conn_r);
|
||||
$order_by = $this->buildOrderByClause($conn_r);
|
||||
$limit = $this->buildLimitClause($conn_r);
|
||||
|
||||
return $question->loadAllFromArray(
|
||||
queryfx_all(
|
||||
$conn_r,
|
||||
'%Q %Q %Q %Q',
|
||||
$select,
|
||||
$where,
|
||||
$order_by,
|
||||
$limit));
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
<?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 PhabricatorSearchPonderIndexer
|
||||
extends PhabricatorSearchDocumentIndexer {
|
||||
|
||||
public static function indexQuestion(PonderQuestion $question) {
|
||||
|
||||
$doc = new PhabricatorSearchAbstractDocument();
|
||||
$doc->setPHID($question->getPHID());
|
||||
$doc->setDocumentType(PhabricatorPHIDConstants::PHID_TYPE_QUES);
|
||||
$doc->setDocumentTitle($question->getTitle());
|
||||
$doc->setDocumentCreated($question->getDateCreated());
|
||||
$doc->setDocumentModified($question->getDateModified());
|
||||
|
||||
$doc->addField(
|
||||
PhabricatorSearchField::FIELD_BODY,
|
||||
$question->getContent());
|
||||
|
||||
$doc->addRelationship(
|
||||
PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR,
|
||||
$question->getAuthorPHID(),
|
||||
PhabricatorPHIDConstants::PHID_TYPE_USER,
|
||||
$question->getDateCreated());
|
||||
|
||||
$answers = $question->getAnswers();
|
||||
$touches = array();
|
||||
foreach ($answers as $comment) {
|
||||
if (strlen($comment->getContent())) {
|
||||
$doc->addField(
|
||||
PhabricatorSearchField::FIELD_COMMENT,
|
||||
$comment->getContent());
|
||||
}
|
||||
|
||||
$author = $comment->getAuthorPHID();
|
||||
$touches[$author] = $comment->getDateCreated();
|
||||
}
|
||||
|
||||
self::reindexAbstractDocument($doc);
|
||||
}
|
||||
}
|
127
src/applications/ponder/storage/PonderAnswer.php
Normal file
127
src/applications/ponder/storage/PonderAnswer.php
Normal file
|
@ -0,0 +1,127 @@
|
|||
<?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 PonderAnswer extends PonderDAO
|
||||
implements PhabricatorMarkupInterface, PonderVotableInterface {
|
||||
|
||||
const MARKUP_FIELD_CONTENT = 'markup:content';
|
||||
|
||||
protected $phid;
|
||||
protected $authorPHID;
|
||||
protected $questionID;
|
||||
|
||||
protected $content;
|
||||
protected $contentSource;
|
||||
|
||||
protected $voteCount;
|
||||
private $vote;
|
||||
private $question = null;
|
||||
|
||||
public function setQuestion($question) {
|
||||
$this->question = $question;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getQuestion() {
|
||||
return $this->question;
|
||||
}
|
||||
|
||||
public function setUserVote($vote) {
|
||||
$this->vote = $vote['data'];
|
||||
if (!$this->vote) {
|
||||
$this->vote = PonderConstants::NONE_VOTE;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUserVote() {
|
||||
return $this->vote;
|
||||
}
|
||||
|
||||
public function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_AUX_PHID => true,
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public function setTitle($title) {
|
||||
$this->title = $title;
|
||||
if (!$this->getID()) {
|
||||
$this->originalTitle = $title;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function generatePHID() {
|
||||
return PhabricatorPHID::generateNewPHID(
|
||||
PhabricatorPHIDConstants::PHID_TYPE_ANSW);
|
||||
}
|
||||
|
||||
public function setContentSource(PhabricatorContentSource $content_source) {
|
||||
$this->contentSource = $content_source->serialize();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContentSource() {
|
||||
return PhabricatorContentSource::newFromSerialized($this->contentSource);
|
||||
}
|
||||
|
||||
public function getAnswers() {
|
||||
return $this->loadRelatives(new PonderAnswer(), "questionID");
|
||||
}
|
||||
|
||||
public function getMarkupField() {
|
||||
return self::MARKUP_FIELD_CONTENT;
|
||||
}
|
||||
|
||||
// Markup interface
|
||||
|
||||
public function getMarkupFieldKey($field) {
|
||||
$hash = PhabricatorHash::digest($this->getMarkupText($field));
|
||||
$id = $this->getID();
|
||||
return "ponder:A{$id}:{$field}:{$hash}";
|
||||
}
|
||||
|
||||
public function getMarkupText($field) {
|
||||
return $this->getContent();
|
||||
}
|
||||
|
||||
public function newMarkupEngine($field) {
|
||||
return PhabricatorMarkupEngine::newPonderMarkupEngine();
|
||||
}
|
||||
|
||||
public function didMarkupText(
|
||||
$field,
|
||||
$output,
|
||||
PhutilMarkupEngine $engine) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function shouldUseMarkupCache($field) {
|
||||
return (bool)$this->getID();
|
||||
}
|
||||
|
||||
// votable interface
|
||||
public function getUserVoteEdgeType() {
|
||||
return PhabricatorEdgeConfig::TYPE_VOTING_USER_HAS_ANSWER;
|
||||
}
|
||||
|
||||
public function getVotablePHID() {
|
||||
return $this->getPHID();
|
||||
}
|
||||
}
|
25
src/applications/ponder/storage/PonderDAO.php
Normal file
25
src/applications/ponder/storage/PonderDAO.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?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 PonderDAO extends PhabricatorLiskDAO {
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'ponder';
|
||||
}
|
||||
|
||||
}
|
141
src/applications/ponder/storage/PonderQuestion.php
Normal file
141
src/applications/ponder/storage/PonderQuestion.php
Normal file
|
@ -0,0 +1,141 @@
|
|||
<?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 PonderQuestion extends PonderDAO
|
||||
implements PhabricatorMarkupInterface, PonderVotableInterface {
|
||||
|
||||
const MARKUP_FIELD_CONTENT = 'markup:content';
|
||||
|
||||
protected $title;
|
||||
protected $phid;
|
||||
|
||||
protected $authorPHID;
|
||||
protected $content;
|
||||
protected $contentSource;
|
||||
|
||||
protected $voteCount;
|
||||
protected $answerCount;
|
||||
protected $heat;
|
||||
|
||||
private $answers;
|
||||
private $vote;
|
||||
|
||||
public function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_AUX_PHID => true,
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public function generatePHID() {
|
||||
return PhabricatorPHID::generateNewPHID(
|
||||
PhabricatorPHIDConstants::PHID_TYPE_QUES);
|
||||
}
|
||||
|
||||
public function setContentSource(PhabricatorContentSource $content_source) {
|
||||
$this->contentSource = $content_source->serialize();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContentSource() {
|
||||
return PhabricatorContentSource::newFromSerialized($this->contentSource);
|
||||
}
|
||||
|
||||
public function attachRelated($user_phid) {
|
||||
$this->answers = $this->loadRelatives(new PonderAnswer(), "questionID");
|
||||
$qa_phids = mpull($this->answers, 'getPHID') + array($this->getPHID());
|
||||
|
||||
$edges = id(new PhabricatorEdgeQuery())
|
||||
->withSourcePHIDs(array($user_phid))
|
||||
->withDestinationPHIDs($qa_phids)
|
||||
->withEdgeTypes(
|
||||
array(
|
||||
PhabricatorEdgeConfig::TYPE_VOTING_USER_HAS_QUESTION,
|
||||
PhabricatorEdgeConfig::TYPE_VOTING_USER_HAS_ANSWER
|
||||
))
|
||||
->needEdgeData(true)
|
||||
->execute();
|
||||
|
||||
$question_edge =
|
||||
$edges[$user_phid][PhabricatorEdgeConfig::TYPE_VOTING_USER_HAS_QUESTION];
|
||||
$answer_edges =
|
||||
$edges[$user_phid][PhabricatorEdgeConfig::TYPE_VOTING_USER_HAS_ANSWER];
|
||||
$edges = null;
|
||||
|
||||
$this->setUserVote(idx($question_edge, $this->getPHID()));
|
||||
foreach ($this->answers as $answer) {
|
||||
$answer->setQuestion($this);
|
||||
$answer->setUserVote(idx($answer_edges, $answer->getPHID()));
|
||||
}
|
||||
}
|
||||
|
||||
public function setUserVote($vote) {
|
||||
$this->vote = $vote['data'];
|
||||
if (!$this->vote) {
|
||||
$this->vote = PonderConstants::NONE_VOTE;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUserVote() {
|
||||
return $this->vote;
|
||||
}
|
||||
|
||||
public function getAnswers() {
|
||||
return $this->answers;
|
||||
}
|
||||
|
||||
public function getMarkupField() {
|
||||
return self::MARKUP_FIELD_CONTENT;
|
||||
}
|
||||
|
||||
// Markup interface
|
||||
|
||||
public function getMarkupFieldKey($field) {
|
||||
$hash = PhabricatorHash::digest($this->getMarkupText($field));
|
||||
$id = $this->getID();
|
||||
return "ponder:Q{$id}:{$field}:{$hash}";
|
||||
}
|
||||
|
||||
public function getMarkupText($field) {
|
||||
return $this->getContent();
|
||||
}
|
||||
|
||||
public function newMarkupEngine($field) {
|
||||
return PhabricatorMarkupEngine::newPonderMarkupEngine();
|
||||
}
|
||||
|
||||
public function didMarkupText(
|
||||
$field,
|
||||
$output,
|
||||
PhutilMarkupEngine $engine) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function shouldUseMarkupCache($field) {
|
||||
return (bool)$this->getID();
|
||||
}
|
||||
|
||||
// votable interface
|
||||
public function getUserVoteEdgeType() {
|
||||
return PhabricatorEdgeConfig::TYPE_VOTING_USER_HAS_QUESTION;
|
||||
}
|
||||
|
||||
public function getVotablePHID() {
|
||||
return $this->getPHID();
|
||||
}
|
||||
}
|
24
src/applications/ponder/storage/PonderVotableInterface.php
Normal file
24
src/applications/ponder/storage/PonderVotableInterface.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?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.
|
||||
*/
|
||||
|
||||
interface PonderVotableInterface {
|
||||
|
||||
public function getUserVoteEdgeType();
|
||||
public function getVotablePHID();
|
||||
|
||||
}
|
97
src/applications/ponder/view/PonderAddAnswerView.php
Normal file
97
src/applications/ponder/view/PonderAddAnswerView.php
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?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 PonderAddAnswerView extends AphrontView {
|
||||
|
||||
private $question;
|
||||
private $user;
|
||||
private $actionURI;
|
||||
private $draft;
|
||||
|
||||
public function setQuestion($question) {
|
||||
$this->question = $question;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUser(PhabricatorUser $user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setActionURI($uri) {
|
||||
$this->actionURI = $uri;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('ponder-core-view-css');
|
||||
|
||||
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
|
||||
|
||||
$question = $this->question;
|
||||
|
||||
$panel = id(new AphrontPanelView())
|
||||
->addClass("ponder-panel")
|
||||
->setHeader("Your Answer:");
|
||||
|
||||
$form = new AphrontFormView();
|
||||
$form
|
||||
->setUser($this->user)
|
||||
->setAction($this->actionURI)
|
||||
->addHiddenInput('question_id', $question->getID())
|
||||
->appendChild(
|
||||
id(new AphrontFormTextAreaControl())
|
||||
->setName('answer')
|
||||
->setID('answer-content')
|
||||
->setEnableDragAndDropFileUploads(true)
|
||||
->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' : 'Make it so.'));
|
||||
|
||||
$panel->appendChild($form);
|
||||
$panel->appendChild(
|
||||
'<div class="aphront-panel-flush">'.
|
||||
'<div id="answer-preview">'.
|
||||
'<span class="aphront-panel-preview-loading-text">'.
|
||||
'Loading answer preview...'.
|
||||
'</span>'.
|
||||
'</div>'.
|
||||
'</div>'
|
||||
);
|
||||
|
||||
Javelin::initBehavior(
|
||||
'ponder-feedback-preview',
|
||||
array(
|
||||
'uri' => '/ponder/answer/preview/',
|
||||
'content' => 'answer-content',
|
||||
'preview' => 'answer-preview',
|
||||
'question_id' => $question->getID()
|
||||
));
|
||||
|
||||
return $panel->render();
|
||||
}
|
||||
}
|
89
src/applications/ponder/view/PonderAnswerListView.php
Normal file
89
src/applications/ponder/view/PonderAnswerListView.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?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 PonderAnswerListView extends AphrontView {
|
||||
|
||||
private $question;
|
||||
private $handles;
|
||||
private $user;
|
||||
private $answers;
|
||||
|
||||
public function setQuestion($question) {
|
||||
$this->question = $question;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHandles(array $handles) {
|
||||
assert_instances_of($handles, 'PhabricatorObjectHandle');
|
||||
$this->handles = $handles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUser(PhabricatorUser $user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setAnswers(array $answers) {
|
||||
assert_instances_of($answers, 'PonderAnswer');
|
||||
|
||||
$this->answers = array();
|
||||
|
||||
// group by descreasing score, randomizing
|
||||
// order within groups
|
||||
$by_score = mgroup($answers, 'getVoteCount');
|
||||
$scores = array_keys($by_score);
|
||||
rsort($scores);
|
||||
|
||||
foreach ($scores as $score) {
|
||||
$group = $by_score[$score];
|
||||
shuffle($group);
|
||||
foreach ($group as $cur_answer) {
|
||||
$this->answers[] = $cur_answer;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('ponder-post-css');
|
||||
|
||||
$question = $this->question;
|
||||
$user = $this->user;
|
||||
$handles = $this->handles;
|
||||
|
||||
$panel = id(new AphrontPanelView())
|
||||
->addClass("ponder-panel")
|
||||
->setHeader("Responses:");
|
||||
|
||||
foreach ($this->answers as $cur_answer) {
|
||||
$view = new PonderCommentBodyView();
|
||||
$view
|
||||
->setQuestion($question)
|
||||
->setTarget($cur_answer)
|
||||
->setAction(PonderConstants::ANSWERED_LITERAL)
|
||||
->setHandles($handles)
|
||||
->setUser($user);
|
||||
|
||||
$panel->appendChild($view);
|
||||
}
|
||||
|
||||
return $panel->render();
|
||||
}
|
||||
}
|
93
src/applications/ponder/view/PonderAnswerSummaryView.php
Normal file
93
src/applications/ponder/view/PonderAnswerSummaryView.php
Normal file
|
@ -0,0 +1,93 @@
|
|||
<?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 PonderAnswerSummaryView extends AphrontView {
|
||||
private $user;
|
||||
private $answer;
|
||||
private $handles;
|
||||
|
||||
public function setAnswer($answer) {
|
||||
$this->answer = $answer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHandles($handles) {
|
||||
$this->handles = $handles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUser(PhabricatorUser $user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
private static function abbreviate($w) {
|
||||
return phutil_utf8_shorten($w, 60);
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('ponder-feed-view-css');
|
||||
|
||||
$user = $this->user;
|
||||
$answer = $this->answer;
|
||||
$question = $answer->getQuestion();
|
||||
$author_phid = $question->getAuthorPHID();
|
||||
$handles = $this->handles;
|
||||
|
||||
$votecount =
|
||||
'<div class="ponder-summary-votes">'.
|
||||
phutil_escape_html($answer->getVoteCount()).
|
||||
'<div class="ponder-question-label">'.
|
||||
'votes'.
|
||||
'</div>'.
|
||||
'</div>';
|
||||
|
||||
$title =
|
||||
'<h2 class="ponder-question-title">'.
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
"href" => id(new PhutilURI('/Q' . $question->getID()))
|
||||
->setFragment('A' . $answer->getID())
|
||||
),
|
||||
phutil_escape_html('A' . $answer->getID() . ' ' .
|
||||
self::abbreviate($answer->getContent())
|
||||
)
|
||||
).
|
||||
'</h2>';
|
||||
|
||||
$rhs =
|
||||
'<div class="ponder-metadata">'.
|
||||
$title.
|
||||
'<span class="ponder-small-metadata">'.
|
||||
phutil_escape_html(
|
||||
'answer to "'. self::abbreviate($question->getTitle()). '" on ' .
|
||||
phabricator_datetime($answer->getDateCreated(), $user)
|
||||
).
|
||||
'</span>'.
|
||||
'</div>';
|
||||
|
||||
$summary =
|
||||
'<div class="ponder-answer-summary">'.
|
||||
$votecount.
|
||||
$rhs.
|
||||
'</div>';
|
||||
|
||||
return $summary;
|
||||
}
|
||||
}
|
149
src/applications/ponder/view/PonderCommentBodyView.php
Normal file
149
src/applications/ponder/view/PonderCommentBodyView.php
Normal file
|
@ -0,0 +1,149 @@
|
|||
<?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 PonderCommentBodyView extends AphrontView {
|
||||
|
||||
private $target;
|
||||
private $question;
|
||||
private $handles;
|
||||
private $preview;
|
||||
private $anchorName;
|
||||
private $user;
|
||||
private $action;
|
||||
|
||||
public function setQuestion($question) {
|
||||
$this->question = $question;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setTarget($target) {
|
||||
$this->target = $target;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setAction($action) {
|
||||
$this->action = $action;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHandles(array $handles) {
|
||||
assert_instances_of($handles, 'PhabricatorObjectHandle');
|
||||
$this->handles = $handles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setPreview($preview) {
|
||||
$this->preview = $preview;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUser(PhabricatorUser $user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
|
||||
if (!$this->user) {
|
||||
throw new Exception("Call setUser() before rendering!");
|
||||
}
|
||||
|
||||
require_celerity_resource('phabricator-remarkup-css');
|
||||
require_celerity_resource('ponder-post-css');
|
||||
|
||||
$user = $this->user;
|
||||
$question = $this->question;
|
||||
$target = $this->target;
|
||||
$content = $target->getContent();
|
||||
$info = array();
|
||||
|
||||
|
||||
$content = PhabricatorMarkupEngine::renderOneObject(
|
||||
$target,
|
||||
$target->getMarkupField());
|
||||
|
||||
$content =
|
||||
'<div class="phabricator-remarkup">'.
|
||||
$content.
|
||||
'</div>';
|
||||
|
||||
$author = $this->handles[$target->getAuthorPHID()];
|
||||
$actions = array($author->renderLink().' '.$this->action);
|
||||
$author_link = $author->renderLink();
|
||||
$xaction_view = id(new PhabricatorTransactionView())
|
||||
->setUser($user)
|
||||
->setImageURI($author->getImageURI())
|
||||
->setContentSource($target->getContentSource())
|
||||
->setActions($actions);
|
||||
|
||||
if ($this->target instanceof PonderAnswer) {
|
||||
$xaction_view->addClass("ponder-answer");
|
||||
}
|
||||
else {
|
||||
$xaction_view->addClass("ponder-question");
|
||||
}
|
||||
|
||||
if ($this->preview) {
|
||||
$xaction_view->setIsPreview($this->preview);
|
||||
} else {
|
||||
$xaction_view->setEpoch($target->getDateCreated());
|
||||
if ($this->target instanceof PonderAnswer) {
|
||||
$anchor_text = 'Q' . $question->getID(). '#A' . $target->getID();
|
||||
$xaction_view->setAnchor('A'.$target->getID(), $anchor_text);
|
||||
$xaction_view->addClass("ponder-answer");
|
||||
}
|
||||
}
|
||||
|
||||
$xaction_view->appendChild(
|
||||
'<div class="ponder-post-core">'.
|
||||
$content.
|
||||
'</div>'
|
||||
);
|
||||
|
||||
$outerview = $xaction_view;
|
||||
if (!$this->preview) {
|
||||
$outerview =
|
||||
id(new PonderVotableView())
|
||||
->setPHID($target->getPHID())
|
||||
->setCount($target->getVoteCount())
|
||||
->setVote($target->getUserVote());
|
||||
|
||||
if ($this->target instanceof PonderAnswer) {
|
||||
$outerview->setURI('/ponder/answer/vote/');
|
||||
}
|
||||
else {
|
||||
$outerview->setURI('/ponder/question/vote/');
|
||||
}
|
||||
|
||||
$outerview->appendChild($xaction_view);
|
||||
}
|
||||
|
||||
return $outerview->render();
|
||||
}
|
||||
|
||||
private function renderHandleList(array $phids) {
|
||||
$result = array();
|
||||
foreach ($phids as $phid) {
|
||||
$result[] = $this->handles[$phid]->renderLink();
|
||||
}
|
||||
return implode(', ', $result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
72
src/applications/ponder/view/PonderQuestionDetailView.php
Normal file
72
src/applications/ponder/view/PonderQuestionDetailView.php
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?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 PonderQuestionDetailView extends AphrontView {
|
||||
|
||||
private $question;
|
||||
private $user;
|
||||
private $handles;
|
||||
|
||||
public function setQuestion($question) {
|
||||
$this->question = $question;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUser($user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHandles($handles) {
|
||||
$this->handles = $handles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('ponder-core-view-css');
|
||||
|
||||
$question = $this->question;
|
||||
$handles = $this->handles;
|
||||
$user = $this->user;
|
||||
|
||||
$panel = id(new AphrontPanelView())
|
||||
->addClass("ponder-panel")
|
||||
->setHeader($this->renderObjectLink().' '.$question->getTitle());
|
||||
|
||||
$contentview = new PonderCommentBodyView();
|
||||
$contentview
|
||||
->setTarget($question)
|
||||
->setQuestion($question)
|
||||
->setUser($user)
|
||||
->setHandles($handles)
|
||||
->setAction(PonderConstants::ASKED_LITERAL);
|
||||
|
||||
$panel->appendChild($contentview);
|
||||
|
||||
return $panel->render();
|
||||
}
|
||||
|
||||
private function renderObjectLink() {
|
||||
return phutil_render_tag(
|
||||
'a',
|
||||
array('href' => '/Q' . $this->question->getID()),
|
||||
"Q". phutil_escape_html($this->question->getID())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
102
src/applications/ponder/view/PonderQuestionFeedView.php
Normal file
102
src/applications/ponder/view/PonderQuestionFeedView.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 PonderQuestionFeedView extends AphrontView {
|
||||
private $user;
|
||||
private $offset;
|
||||
private $data;
|
||||
private $pagesize;
|
||||
private $uri;
|
||||
private $param;
|
||||
|
||||
public function setUser(PhabricatorUser $user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setOffset($offset) {
|
||||
$this->offset = $offset;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setData($data) {
|
||||
$this->data = $data;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setPageSize($pagesize) {
|
||||
$this->pagesize = $pagesize;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHandles($handles) {
|
||||
$this->handles = $handles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setURI($uri, $param) {
|
||||
$this->uri = $uri;
|
||||
$this->param = $param;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('ponder-core-view-css');
|
||||
require_celerity_resource('ponder-feed-view-css');
|
||||
|
||||
$user = $this->user;
|
||||
$offset = $this->offset;
|
||||
$data = $this->data;
|
||||
$handles = $this->handles;
|
||||
$uri = $this->uri;
|
||||
$param = $this->param;
|
||||
$pagesize = $this->pagesize;
|
||||
|
||||
$panel = id(new AphrontPanelView())
|
||||
->setHeader("Popular Questions")
|
||||
->addClass("ponder-panel");
|
||||
|
||||
$panel->addButton(
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => "/ponder/question/ask/",
|
||||
'class' => 'green button',
|
||||
),
|
||||
"Ask a question"));
|
||||
|
||||
$pagebuttons = id(new AphrontPagerView())
|
||||
->setPageSize($pagesize)
|
||||
->setOffset($offset)
|
||||
->setURI($uri, $param);
|
||||
|
||||
$data = $pagebuttons->sliceResults($data);
|
||||
|
||||
|
||||
foreach ($data as $question) {
|
||||
$cur = id(new PonderQuestionSummaryView())
|
||||
->setUser($user)
|
||||
->setQuestion($question)
|
||||
->setHandles($handles);
|
||||
$panel->appendChild($cur);
|
||||
}
|
||||
|
||||
$panel->appendChild($pagebuttons);
|
||||
return $panel->render();
|
||||
}
|
||||
}
|
105
src/applications/ponder/view/PonderQuestionSummaryView.php
Normal file
105
src/applications/ponder/view/PonderQuestionSummaryView.php
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?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 PonderQuestionSummaryView extends AphrontView {
|
||||
private $user;
|
||||
private $question;
|
||||
private $handles;
|
||||
|
||||
public function setQuestion($question) {
|
||||
$this->question = $question;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHandles($handles) {
|
||||
$this->handles = $handles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUser(PhabricatorUser $user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('ponder-feed-view-css');
|
||||
|
||||
$user = $this->user;
|
||||
$question = $this->question;
|
||||
$author_phid = $question->getAuthorPHID();
|
||||
$handles = $this->handles;
|
||||
|
||||
$authorlink = $handles[$author_phid]
|
||||
->renderLink();
|
||||
|
||||
$votecount =
|
||||
'<div class="ponder-summary-votes">'.
|
||||
phutil_escape_html($question->getVoteCount()).
|
||||
'<div class="ponder-question-label">'.
|
||||
'votes'.
|
||||
'</div>'.
|
||||
'</div>';
|
||||
|
||||
$answerclass = "ponder-summary-answers";
|
||||
if ($question->getAnswercount() == 0) {
|
||||
$answerclass .= " ponder-not-answered";
|
||||
}
|
||||
$answercount =
|
||||
'<div class="ponder-summary-answers">'.
|
||||
phutil_escape_html($question->getAnswerCount()).
|
||||
'<div class="ponder-question-label">'.
|
||||
'answers'.
|
||||
'</div>'.
|
||||
'</div>';
|
||||
|
||||
|
||||
$title =
|
||||
'<h2 class="ponder-question-title">'.
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
"href" => '/Q' . $question->getID(),
|
||||
),
|
||||
phutil_escape_html(
|
||||
'Q' . $question->getID() .
|
||||
' ' . $question->getTitle()
|
||||
)
|
||||
) .
|
||||
'</h2>';
|
||||
|
||||
$rhs =
|
||||
'<div class="ponder-metadata">'.
|
||||
$title.
|
||||
'<span class="ponder-small-metadata">'.
|
||||
'asked on '.
|
||||
phabricator_datetime($question->getDateCreated(), $user).
|
||||
' by ' . $authorlink.
|
||||
'</span>'.
|
||||
'</div>';
|
||||
|
||||
$summary =
|
||||
'<div class="ponder-question-summary">'.
|
||||
$votecount.
|
||||
$answercount.
|
||||
$rhs.
|
||||
'</div>';
|
||||
|
||||
|
||||
return $summary;
|
||||
}
|
||||
}
|
159
src/applications/ponder/view/PonderUserProfileView.php
Normal file
159
src/applications/ponder/view/PonderUserProfileView.php
Normal file
|
@ -0,0 +1,159 @@
|
|||
<?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 PonderUserProfileView extends AphrontView {
|
||||
private $user;
|
||||
private $questionoffset;
|
||||
private $answeroffset;
|
||||
private $questions;
|
||||
private $answers;
|
||||
private $pagesize;
|
||||
private $uri;
|
||||
private $qparam;
|
||||
private $aparam;
|
||||
|
||||
public function setUser(PhabricatorUser $user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setQuestionOffset($offset) {
|
||||
$this->questionoffset = $offset;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setAnswerOffset($offset) {
|
||||
$this->answeroffset = $offset;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setQuestions($data) {
|
||||
$this->questions = $data;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setAnswers($data) {
|
||||
$this->answers = $data;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setPageSize($pagesize) {
|
||||
$this->pagesize = $pagesize;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHandles($handles) {
|
||||
$this->handles = $handles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setURI($uri, $qparam, $aparam) {
|
||||
$this->uri = $uri;
|
||||
$this->qparam = $qparam;
|
||||
$this->aparam = $aparam;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('ponder-core-view-css');
|
||||
require_celerity_resource('ponder-feed-view-css');
|
||||
|
||||
$user = $this->user;
|
||||
$qoffset = $this->questionoffset;
|
||||
$aoffset = $this->answeroffset;
|
||||
$questions = $this->questions;
|
||||
$answers = $this->answers;
|
||||
$handles = $this->handles;
|
||||
$uri = $this->uri;
|
||||
$qparam = $this->qparam;
|
||||
$aparam = $this->aparam;
|
||||
$pagesize = $this->pagesize;
|
||||
|
||||
|
||||
// display questions
|
||||
$question_panel = id(new AphrontPanelView())
|
||||
->setHeader("Your Questions")
|
||||
->addClass("ponder-panel");
|
||||
|
||||
$question_panel->addButton(
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => "/ponder/question/ask/",
|
||||
'class' => 'green button',
|
||||
),
|
||||
"Ask a question"));
|
||||
|
||||
$qpagebuttons = id(new AphrontPagerView())
|
||||
->setPageSize($pagesize)
|
||||
->setOffset($qoffset)
|
||||
->setURI(
|
||||
$uri->alter(
|
||||
$aparam,
|
||||
$aoffset),
|
||||
$qparam);
|
||||
|
||||
$questions = $qpagebuttons->sliceResults($questions);
|
||||
|
||||
foreach ($questions as $question) {
|
||||
$cur = id(new PonderQuestionSummaryView())
|
||||
->setUser($user)
|
||||
->setQuestion($question)
|
||||
->setHandles($handles);
|
||||
$question_panel->appendChild($cur);
|
||||
}
|
||||
|
||||
$question_panel->appendChild($qpagebuttons);
|
||||
|
||||
// display answers
|
||||
$answer_panel = id(new AphrontPanelView())
|
||||
->setHeader("Your Answers")
|
||||
->addClass("ponder-panel")
|
||||
->appendChild(
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array('id' => 'answers'),
|
||||
"")
|
||||
);
|
||||
|
||||
$apagebuttons = id(new AphrontPagerView())
|
||||
->setPageSize($pagesize)
|
||||
->setOffset($aoffset)
|
||||
->setURI(
|
||||
$uri
|
||||
->alter(
|
||||
$qparam,
|
||||
$qoffset)
|
||||
->setFragment("answers"),
|
||||
$aparam);
|
||||
|
||||
$answers = $apagebuttons->sliceResults($answers);
|
||||
|
||||
foreach ($answers as $answer) {
|
||||
$cur = id(new PonderAnswerSummaryView())
|
||||
->setUser($user)
|
||||
->setAnswer($answer)
|
||||
->setHandles($handles);
|
||||
$answer_panel->appendChild($cur);
|
||||
}
|
||||
|
||||
$answer_panel->appendChild($apagebuttons);
|
||||
|
||||
return $question_panel->render() . $answer_panel->render();
|
||||
}
|
||||
}
|
70
src/applications/ponder/view/PonderVotableView.php
Normal file
70
src/applications/ponder/view/PonderVotableView.php
Normal file
|
@ -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 PonderVotableView extends AphrontView {
|
||||
|
||||
private $phid;
|
||||
private $uri;
|
||||
private $count;
|
||||
private $vote;
|
||||
|
||||
public function setPHID($phid) {
|
||||
$this->phid = $phid;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setURI($uri) {
|
||||
$this->uri = $uri;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCount($count) {
|
||||
$this->count = $count;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setVote($vote) {
|
||||
$this->vote = $vote;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('ponder-vote-css');
|
||||
require_celerity_resource('javelin-behavior-ponder-votebox');
|
||||
|
||||
Javelin::initBehavior(
|
||||
'ponder-votebox',
|
||||
array(
|
||||
'nodeid' => $this->phid,
|
||||
'vote' => $this->vote,
|
||||
'count' => $this->count,
|
||||
'uri' => $this->uri
|
||||
));
|
||||
|
||||
$content =
|
||||
'<div class="ponder-votable">'.
|
||||
'<div id="'.phutil_escape_html($this->phid).'" class="ponder-votebox">
|
||||
</div>'.
|
||||
$this->renderChildren().
|
||||
'<div class="ponder-votable-bottom"></div>'.
|
||||
'</div>';
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
}
|
|
@ -26,6 +26,7 @@ final class PhabricatorSearchScope {
|
|||
const SCOPE_OPEN_TASKS = 'open-tasks';
|
||||
const SCOPE_COMMITS = 'commits';
|
||||
const SCOPE_WIKI = 'wiki';
|
||||
const SCOPE_QUESTIONS = 'questions';
|
||||
|
||||
public static function getScopeOptions() {
|
||||
return array(
|
||||
|
@ -34,6 +35,7 @@ final class PhabricatorSearchScope {
|
|||
self::SCOPE_WIKI => 'Wiki Documents',
|
||||
self::SCOPE_OPEN_REVISIONS => 'Open Revisions',
|
||||
self::SCOPE_COMMITS => 'Commits',
|
||||
self::SCOPE_QUESTIONS => 'Ponder Questions',
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ final class PhabricatorSearchAbstractDocument {
|
|||
PhabricatorPHIDConstants::PHID_TYPE_TASK => 'Maniphest Tasks',
|
||||
PhabricatorPHIDConstants::PHID_TYPE_WIKI => 'Phriction Documents',
|
||||
PhabricatorPHIDConstants::PHID_TYPE_USER => 'Phabricator Users',
|
||||
PhabricatorPHIDConstants::PHID_TYPE_QUES => 'Ponder Questions',
|
||||
) + $more;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,11 @@ final class PhabricatorEdgeConfig extends PhabricatorEdgeConstants {
|
|||
const TYPE_COMMIT_HAS_PROJECT = 15;
|
||||
const TYPE_PROJECT_HAS_COMMIT = 16;
|
||||
|
||||
const TYPE_QUESTION_HAS_VOTING_USER = 17;
|
||||
const TYPE_VOTING_USER_HAS_QUESTION = 18;
|
||||
const TYPE_ANSWER_HAS_VOTING_USER = 19;
|
||||
CONST TYPE_VOTING_USER_HAS_ANSWER = 20;
|
||||
|
||||
const TYPE_TEST_NO_CYCLE = 9000;
|
||||
|
||||
public static function getInverse($edge_type) {
|
||||
|
@ -71,6 +76,12 @@ final class PhabricatorEdgeConfig extends PhabricatorEdgeConstants {
|
|||
self::TYPE_COMMIT_HAS_PROJECT => self::TYPE_PROJECT_HAS_COMMIT,
|
||||
self::TYPE_PROJECT_HAS_COMMIT => self::TYPE_COMMIT_HAS_PROJECT,
|
||||
|
||||
self::TYPE_QUESTION_HAS_VOTING_USER =>
|
||||
self::TYPE_VOTING_USER_HAS_QUESTION,
|
||||
self::TYPE_VOTING_USER_HAS_QUESTION =>
|
||||
self::TYPE_QUESTION_HAS_VOTING_USER,
|
||||
self::TYPE_ANSWER_HAS_VOTING_USER => self::TYPE_VOTING_USER_HAS_ANSWER,
|
||||
self::TYPE_VOTING_USER_HAS_ANSWER => self::TYPE_ANSWER_HAS_VOTING_USER,
|
||||
);
|
||||
|
||||
return idx($map, $edge_type);
|
||||
|
@ -98,6 +109,8 @@ final class PhabricatorEdgeConfig extends PhabricatorEdgeConstants {
|
|||
PhabricatorPHIDConstants::PHID_TYPE_TOBJ => 'HarbormasterObject',
|
||||
PhabricatorPHIDConstants::PHID_TYPE_BLOG => 'PhameBlog',
|
||||
PhabricatorPHIDConstants::PHID_TYPE_POST => 'PhamePost',
|
||||
PhabricatorPHIDConstants::PHID_TYPE_QUES => 'PonderQuestion',
|
||||
PhabricatorPHIDConstants::PHID_TYPE_ANSW => 'PonderAnswer',
|
||||
);
|
||||
|
||||
$class = idx($class_map, $phid_type);
|
||||
|
|
|
@ -330,6 +330,11 @@ final class PhabricatorMarkupEngine {
|
|||
}
|
||||
|
||||
|
||||
public static function newPonderMarkupEngine(array $options = array()) {
|
||||
return self::newMarkupEngine($options);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @task engine
|
||||
*/
|
||||
|
@ -406,6 +411,8 @@ final class PhabricatorMarkupEngine {
|
|||
$rules[] = new PhabricatorRemarkupRuleManiphest();
|
||||
$rules[] = new PhabricatorRemarkupRulePaste();
|
||||
|
||||
$rules[] = new PonderRuleQuestion();
|
||||
|
||||
if ($options['macros']) {
|
||||
$rules[] = new PhabricatorRemarkupRuleImageMacro();
|
||||
}
|
||||
|
|
29
src/infrastructure/markup/rule/PonderRuleQuestion.php
Normal file
29
src/infrastructure/markup/rule/PonderRuleQuestion.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?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 markup
|
||||
*/
|
||||
final class PonderRuleQuestion
|
||||
extends PhabricatorRemarkupRuleObjectName {
|
||||
|
||||
protected function getObjectNamePrefix() {
|
||||
return 'Q';
|
||||
}
|
||||
}
|
||||
|
|
@ -163,6 +163,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
|||
'type' => 'db',
|
||||
'name' => 'fact',
|
||||
),
|
||||
'db.ponder' => array(
|
||||
'type' => 'db',
|
||||
'name' => 'ponder',
|
||||
),
|
||||
'0000.legacy.sql' => array(
|
||||
'type' => 'sql',
|
||||
'name' => $this->getPatchPath('0000.legacy.sql'),
|
||||
|
@ -952,6 +956,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
|||
'type' => 'sql',
|
||||
'name' => $this->getPatchPath('fact-raw.sql'),
|
||||
),
|
||||
'ponder.sql' => array(
|
||||
'type' => 'sql',
|
||||
'name' => $this->getPatchPath('ponder.sql')
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
25
webroot/rsrc/css/application/ponder/core.css
Normal file
25
webroot/rsrc/css/application/ponder/core.css
Normal file
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* @provides ponder-core-view-css
|
||||
*/
|
||||
|
||||
.ponder-primary-pane {
|
||||
margin: 0 0 0 2em;
|
||||
padding-bottom: 2em;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.ponder-panel {
|
||||
max-width: 800px;
|
||||
font-family : antiqua, verdana, arial;
|
||||
}
|
||||
|
||||
.ponder-panel h1 {
|
||||
padding-bottom: 8px;
|
||||
margin-bottom: 8px;
|
||||
font-size : 1.5em;
|
||||
}
|
||||
|
||||
.ponder-panel .aphront-form-view {
|
||||
border : none;
|
||||
background : none;
|
||||
}
|
74
webroot/rsrc/css/application/ponder/feed.css
Normal file
74
webroot/rsrc/css/application/ponder/feed.css
Normal file
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* @provides ponder-feed-view-css
|
||||
*/
|
||||
|
||||
.ponder-question-summary {
|
||||
width : 100%;
|
||||
background : #DFDFE3;
|
||||
float : left;
|
||||
clear : both;
|
||||
margin-top : 1px;
|
||||
padding : 1px;
|
||||
}
|
||||
|
||||
.ponder-answer-summary {
|
||||
width : 100%;
|
||||
background : #DFDFE3;
|
||||
float : left;
|
||||
clear : both;
|
||||
margin-top : 1px;
|
||||
padding : 1px;
|
||||
}
|
||||
|
||||
.ponder-summary-votes {
|
||||
width : 50px;
|
||||
height : 36pt;
|
||||
font-size : 18pt;
|
||||
text-align : center;
|
||||
background : #EEE;
|
||||
border : 1px solid #BBB;
|
||||
float : left;
|
||||
margin : 2px;
|
||||
padding-top : 2px;
|
||||
}
|
||||
|
||||
.ponder-summary-answers {
|
||||
width : 50px;
|
||||
height : 36pt;
|
||||
font-size : 18pt;
|
||||
text-align : center;
|
||||
background : #EEE;
|
||||
border : 1px solid #BBB;
|
||||
float : left;
|
||||
margin : 2px;
|
||||
padding-top : 2px;
|
||||
}
|
||||
|
||||
.ponder-question-label {
|
||||
font-size : 6pt;
|
||||
}
|
||||
|
||||
h2.ponder-question-title {
|
||||
font-size : 12pt;
|
||||
margin : 2px;
|
||||
padding : 0;
|
||||
}
|
||||
|
||||
h2.ponder-answer-title {
|
||||
font-size : 12pt;
|
||||
margin : 2px;
|
||||
padding : 0;
|
||||
}
|
||||
|
||||
.ponder-metadata {
|
||||
padding-left : 5px;
|
||||
width : 650px;
|
||||
float : left;
|
||||
}
|
||||
|
||||
.ponder-small-metadata {
|
||||
font-size : 7.5pt;
|
||||
color : #555;
|
||||
margin : 0;
|
||||
text-align : right;
|
||||
}
|
34
webroot/rsrc/css/application/ponder/post.css
Normal file
34
webroot/rsrc/css/application/ponder/post.css
Normal file
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
* @provides ponder-post-css
|
||||
*/
|
||||
|
||||
.ponder-post-list {
|
||||
max-width: 1162px;
|
||||
}
|
||||
|
||||
.ponder-add-answer-panel {
|
||||
max-width: 1162px;
|
||||
}
|
||||
|
||||
.ponder-post-list .anchor-target {
|
||||
background-color: #ffffdd;
|
||||
border-color: #ffff00;
|
||||
}
|
||||
|
||||
.ponder-post-core .phabricator-remarkup .remarkup-code-block {
|
||||
width: 88ex;
|
||||
width: 81ch;
|
||||
}
|
||||
|
||||
.phabricator-transaction-view .ponder-question {
|
||||
border-color: #777;
|
||||
}
|
||||
|
||||
.phabricator-transaction-detail .ponder-question {
|
||||
border-color: #777;
|
||||
}
|
||||
|
||||
|
||||
.phabricator-transaction-view .ponder-answer {
|
||||
/* border-color: #203791; */
|
||||
}
|
74
webroot/rsrc/css/application/ponder/vote.css
Normal file
74
webroot/rsrc/css/application/ponder/vote.css
Normal file
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* @provides ponder-vote-css
|
||||
*/
|
||||
|
||||
.ponder-votable {
|
||||
min-height : 120px;
|
||||
}
|
||||
|
||||
.ponder-votable .phabricator-transaction-detail {
|
||||
min-height : 90px;
|
||||
}
|
||||
|
||||
.ponder-votebox {
|
||||
float : left;
|
||||
width : 32px;
|
||||
height : 60px;
|
||||
margin-top : 56px;
|
||||
margin-left : 10px;
|
||||
}
|
||||
|
||||
.ponder-upbutton {
|
||||
border : none;
|
||||
padding : 0;
|
||||
margin : 0;
|
||||
width : 32px;
|
||||
height : 13px;
|
||||
}
|
||||
|
||||
.ponder-downbutton {
|
||||
border : none;
|
||||
padding : 0;
|
||||
margin : 0;
|
||||
width : 32px;
|
||||
height : 13px;
|
||||
}
|
||||
|
||||
.ponder-votecount {
|
||||
width : 32px;
|
||||
height : 22pt;
|
||||
padding : 0;
|
||||
margin : 0;
|
||||
overflow : visible;
|
||||
text-align : center;
|
||||
font-size : 15pt;
|
||||
}
|
||||
|
||||
.ponder-upbutton:hover {
|
||||
cursor : pointer;
|
||||
}
|
||||
|
||||
.ponder-downbutton:hover {
|
||||
cursor : pointer;
|
||||
}
|
||||
|
||||
.ponder-votable-bottom {
|
||||
clear : both;
|
||||
}
|
||||
|
||||
.ponder-upbutton {
|
||||
background : url(/rsrc/image/application/ponder/upvote.png) 0 -13px no-repeat;
|
||||
}
|
||||
|
||||
.ponder-upbutton.ponder-vote-up {
|
||||
background : url(/rsrc/image/application/ponder/upvote.png) 0 0 no-repeat;
|
||||
}
|
||||
|
||||
.ponder-downbutton {
|
||||
background : url(/rsrc/image/application/ponder/downvote.png)
|
||||
0 -13px no-repeat;
|
||||
}
|
||||
|
||||
.ponder-downbutton.ponder-vote-down {
|
||||
background : url(/rsrc/image/application/ponder/downvote.png) 0 0 no-repeat;
|
||||
}
|
BIN
webroot/rsrc/image/app/app_ponder.png
Normal file
BIN
webroot/rsrc/image/app/app_ponder.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.5 KiB |
BIN
webroot/rsrc/image/application/ponder/downvote.png
Normal file
BIN
webroot/rsrc/image/application/ponder/downvote.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 929 B |
BIN
webroot/rsrc/image/application/ponder/upvote.png
Normal file
BIN
webroot/rsrc/image/application/ponder/upvote.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 916 B |
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* @provides javelin-behavior-ponder-feedback-preview
|
||||
* @requires javelin-behavior
|
||||
* javelin-dom
|
||||
* javelin-util
|
||||
* phabricator-shaped-request
|
||||
*/
|
||||
|
||||
JX.behavior('ponder-feedback-preview', function(config) {
|
||||
|
||||
var content = JX.$(config.content);
|
||||
var question_id = config.question_id;
|
||||
|
||||
var callback = function(r) {
|
||||
JX.DOM.setContent(JX.$(config.preview), JX.$H(r));
|
||||
};
|
||||
|
||||
var getdata = function() {
|
||||
var data = {
|
||||
content : content.value,
|
||||
question_id : question_id
|
||||
};
|
||||
return data;
|
||||
};
|
||||
|
||||
var request = new JX.PhabricatorShapedRequest(config.uri, callback, getdata);
|
||||
var trigger = JX.bind(request, request.trigger);
|
||||
|
||||
JX.DOM.listen(content, 'keydown', null, trigger);
|
||||
|
||||
request.start();
|
||||
});
|
76
webroot/rsrc/js/application/ponder/behavior-votebox.js
Normal file
76
webroot/rsrc/js/application/ponder/behavior-votebox.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
* @provides javelin-behavior-ponder-votebox
|
||||
* @requires javelin-behavior
|
||||
* javelin-dom
|
||||
* javelin-util
|
||||
* phabricator-shaped-request
|
||||
*/
|
||||
|
||||
JX.behavior('ponder-votebox', function(config) {
|
||||
|
||||
var node = JX.$(config.nodeid);
|
||||
var vote = config.vote;
|
||||
var count = config.count | 0;
|
||||
var targetURI = config.targetURI;
|
||||
|
||||
var upnode, countnode, downnode;
|
||||
|
||||
// this defines the behavior of the up/downvote
|
||||
// buttons, e.g. clicking 'up' transitions from
|
||||
// an 'up' vote to a 'none' vote
|
||||
var votecycle = {
|
||||
"1" : { up : "0", down : "-1" },
|
||||
"0" : { up : "1", down : "-1" },
|
||||
"-1" : { up : "1", down : "0" }
|
||||
};
|
||||
|
||||
var voteclass = {
|
||||
"0" : "ponder-vote-none",
|
||||
"-1" : "ponder-vote-down",
|
||||
"1" : "ponder-vote-up"
|
||||
};
|
||||
|
||||
function decorate() {
|
||||
upnode = JX.$N('div');
|
||||
countnode = JX.$N('div');
|
||||
downnode = JX.$N('div');
|
||||
node.appendChild(upnode);
|
||||
node.appendChild(countnode);
|
||||
node.appendChild(downnode);
|
||||
JX.DOM.alterClass(upnode, "ponder-upbutton " + voteclass[vote], true);
|
||||
JX.DOM.alterClass(downnode, "ponder-downbutton " + voteclass[vote], true);
|
||||
JX.DOM.alterClass(countnode, "ponder-votecount", true);
|
||||
}
|
||||
|
||||
function update_state() {
|
||||
upnode.className = "ponder-upbutton " + voteclass[vote];
|
||||
downnode.className = "ponder-downbutton " + voteclass[vote];
|
||||
JX.DOM.setContent(countnode, JX.$H(count.toString()));
|
||||
}
|
||||
|
||||
function getdata() {
|
||||
return { phid : config.nodeid, vote : vote };
|
||||
}
|
||||
|
||||
var request = new JX.PhabricatorShapedRequest(config.uri, JX.id, getdata);
|
||||
var trigger = JX.bind(request, request.trigger);
|
||||
|
||||
function handle_upvote(e) {
|
||||
count += votecycle[vote].up - vote;
|
||||
vote = votecycle[vote].up;
|
||||
trigger();
|
||||
update_state();
|
||||
}
|
||||
|
||||
function handle_downvote(e) {
|
||||
count += votecycle[vote].down - vote;
|
||||
vote = votecycle[vote].down;
|
||||
trigger();
|
||||
update_state();
|
||||
}
|
||||
|
||||
decorate();
|
||||
update_state();
|
||||
JX.DOM.listen(upnode, 'click', null, handle_upvote);
|
||||
JX.DOM.listen(downnode, 'click', null, handle_downvote);
|
||||
});
|
Loading…
Reference in a new issue