mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 14:52:41 +01:00
Port the "Slowvote" application
Summary: Port slowvote. This has some style/layout roughness but gets us most of the way there. I'll followup to fix some of the markup issues. Test Plan: Created and voted in several different kinds of poll. Reviewed By: codeblock Reviewers: codeblock, tomo, jungejason, aran, tuomaspelkonen Commenters: aran, jungejason CC: aran, codeblock, jungejason, epriestley Differential Revision: 613
This commit is contained in:
parent
cce786a89f
commit
57097c2874
25 changed files with 1248 additions and 11 deletions
50
resources/sql/patches/056.slowvote.sql
Normal file
50
resources/sql/patches/056.slowvote.sql
Normal file
|
@ -0,0 +1,50 @@
|
|||
CREATE DATABASE phabricator_slowvote;
|
||||
|
||||
CREATE TABLE phabricator_slowvote.slowvote_poll (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
question VARCHAR(255) NOT NULL,
|
||||
phid VARCHAR(64) BINARY NOT NULL,
|
||||
UNIQUE KEY (phid),
|
||||
authorPHID VARCHAR(64) BINARY NOT NULL,
|
||||
responseVisibility INT UNSIGNED NOT NULL,
|
||||
shuffle INT UNSIGNED NOT NULL,
|
||||
method INT UNSIGNED NOT NULL,
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE phabricator_slowvote.slowvote_option (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
pollID INT UNSIGNED NOT NULL,
|
||||
KEY (pollID),
|
||||
name VARCHAR(255) NOT NULL,
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE phabricator_slowvote.slowvote_comment (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
pollID INT UNSIGNED NOT NULL,
|
||||
UNIQUE KEY (pollID, authorPHID),
|
||||
authorPHID VARCHAR(64) BINARY NOT NULL,
|
||||
commentText LONGBLOB NOT NULL,
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE phabricator_slowvote.slowvote_choice (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
pollID INT UNSIGNED NOT NULL,
|
||||
KEY (pollID),
|
||||
optionID INT UNSIGNED NOT NULL,
|
||||
authorPHID VARCHAR(64) BINARY NOT NULL,
|
||||
KEY (authorPHID),
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO phabricator_directory.directory_item
|
||||
(name, description, href, categoryID, sequence, dateCreated, dateModified)
|
||||
VALUES
|
||||
("Slowvote", "Design by committee.", "/vote/", 5, 250,
|
||||
UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
|
|
@ -283,17 +283,6 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/css/application/herald/herald-test.css',
|
||||
),
|
||||
0 =>
|
||||
array(
|
||||
'uri' => '/res/1da00bfe/rsrc/js/javelin/lib/__tests__/URI.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-uri',
|
||||
1 => 'javelin-php-serializer',
|
||||
),
|
||||
'disk' => '/rsrc/js/javelin/lib/__tests__/URI.js',
|
||||
),
|
||||
'javelin-behavior' =>
|
||||
array(
|
||||
'uri' => '/res/b28adfa1/rsrc/js/javelin/lib/behavior.js',
|
||||
|
@ -487,6 +476,17 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/js/application/differential/behavior-show-all-comments.js',
|
||||
),
|
||||
0 =>
|
||||
array(
|
||||
'uri' => '/res/1da00bfe/rsrc/js/javelin/lib/__tests__/URI.js',
|
||||
'type' => 'js',
|
||||
'requires' =>
|
||||
array(
|
||||
0 => 'javelin-uri',
|
||||
1 => 'javelin-php-serializer',
|
||||
),
|
||||
'disk' => '/rsrc/js/javelin/lib/__tests__/URI.js',
|
||||
),
|
||||
'javelin-behavior-differential-show-more' =>
|
||||
array(
|
||||
'uri' => '/res/a766c717/rsrc/js/application/differential/behavior-show-more.js',
|
||||
|
@ -1099,6 +1099,15 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/js/application/core/ShapedRequest.js',
|
||||
),
|
||||
'phabricator-slowvote-css' =>
|
||||
array(
|
||||
'uri' => '/res/2caefc66/rsrc/css/application/slowvote/slowvote.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
'disk' => '/rsrc/css/application/slowvote/slowvote.css',
|
||||
),
|
||||
'phabricator-standard-page-view' =>
|
||||
array(
|
||||
'uri' => '/res/e8238633/rsrc/css/application/base/standard-page-view.css',
|
||||
|
|
|
@ -521,6 +521,15 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSearchSelectController' => 'applications/search/controller/select',
|
||||
'PhabricatorSearchUserIndexer' => 'applications/search/index/indexer/user',
|
||||
'PhabricatorSetup' => 'infrastructure/setup',
|
||||
'PhabricatorSlowvoteChoice' => 'applications/slowvote/storage/choice',
|
||||
'PhabricatorSlowvoteComment' => 'applications/slowvote/storage/comment',
|
||||
'PhabricatorSlowvoteController' => 'applications/slowvote/controller/base',
|
||||
'PhabricatorSlowvoteCreateController' => 'applications/slowvote/controller/create',
|
||||
'PhabricatorSlowvoteDAO' => 'applications/slowvote/storage/base',
|
||||
'PhabricatorSlowvoteListController' => 'applications/slowvote/controller/list',
|
||||
'PhabricatorSlowvoteOption' => 'applications/slowvote/storage/option',
|
||||
'PhabricatorSlowvotePoll' => 'applications/slowvote/storage/poll',
|
||||
'PhabricatorSlowvotePollController' => 'applications/slowvote/controller/poll',
|
||||
'PhabricatorStandardPageView' => 'view/page/standard',
|
||||
'PhabricatorStatusController' => 'applications/status/base',
|
||||
'PhabricatorSyntaxHighlighter' => 'applications/markup/syntax',
|
||||
|
@ -1002,6 +1011,15 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSearchResultView' => 'AphrontView',
|
||||
'PhabricatorSearchSelectController' => 'PhabricatorSearchController',
|
||||
'PhabricatorSearchUserIndexer' => 'PhabricatorSearchDocumentIndexer',
|
||||
'PhabricatorSlowvoteChoice' => 'PhabricatorSlowvoteDAO',
|
||||
'PhabricatorSlowvoteComment' => 'PhabricatorSlowvoteDAO',
|
||||
'PhabricatorSlowvoteController' => 'PhabricatorController',
|
||||
'PhabricatorSlowvoteCreateController' => 'PhabricatorSlowvoteController',
|
||||
'PhabricatorSlowvoteDAO' => 'PhabricatorLiskDAO',
|
||||
'PhabricatorSlowvoteListController' => 'PhabricatorSlowvoteController',
|
||||
'PhabricatorSlowvoteOption' => 'PhabricatorSlowvoteDAO',
|
||||
'PhabricatorSlowvotePoll' => 'PhabricatorSlowvoteDAO',
|
||||
'PhabricatorSlowvotePollController' => 'PhabricatorSlowvoteController',
|
||||
'PhabricatorStandardPageView' => 'AphrontPageView',
|
||||
'PhabricatorStatusController' => 'PhabricatorController',
|
||||
'PhabricatorTaskmasterDaemon' => 'PhabricatorDaemon',
|
||||
|
|
|
@ -334,6 +334,12 @@ class AphrontDefaultApplicationConfiguration
|
|||
'/feed/' => array(
|
||||
'$' => 'PhabricatorFeedStreamController',
|
||||
),
|
||||
|
||||
'/V(?P<id>\d+)$' => 'PhabricatorSlowvotePollController',
|
||||
'/vote/' => array(
|
||||
'(?:view/(?P<view>\w+)/)?$' => 'PhabricatorSlowvoteListController',
|
||||
'create/' => 'PhabricatorSlowvoteCreateController',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ final class PhabricatorPHIDConstants {
|
|||
const PHID_TYPE_OPKG = 'OPKG';
|
||||
const PHID_TYPE_PSTE = 'PSTE';
|
||||
const PHID_TYPE_STRY = 'STRY';
|
||||
const PHID_TYPE_POLL = 'POLL';
|
||||
|
||||
public static function getTypes() {
|
||||
return array(
|
||||
|
@ -47,6 +48,7 @@ final class PhabricatorPHIDConstants {
|
|||
self::PHID_TYPE_PSTE,
|
||||
self::PHID_TYPE_OPKG,
|
||||
self::PHID_TYPE_STRY,
|
||||
self::PHID_TYPE_POLL,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 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 PhabricatorSlowvoteController extends PhabricatorController {
|
||||
|
||||
public function buildStandardPageResponse($view, array $data) {
|
||||
$page = $this->buildStandardPageView();
|
||||
|
||||
$page->setApplicationName('Slowvote');
|
||||
$page->setBaseURI('/vote/');
|
||||
$page->setTitle(idx($data, 'title'));
|
||||
$page->setGlyph("\xE2\x9C\x94");
|
||||
|
||||
$doc_href = PhabricatorEnv::getDoclink('articles/Slowvote_User_Guide.html');
|
||||
$page->setTabs(
|
||||
array(
|
||||
'help' => array(
|
||||
'name' => 'Help',
|
||||
'href' => $doc_href,
|
||||
),
|
||||
),
|
||||
null);
|
||||
|
||||
$page->appendChild($view);
|
||||
|
||||
$response = new AphrontWebpageResponse();
|
||||
return $response->setContent($page->render());
|
||||
}
|
||||
|
||||
}
|
16
src/applications/slowvote/controller/base/__init__.php
Normal file
16
src/applications/slowvote/controller/base/__init__.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/response/webpage');
|
||||
phutil_require_module('phabricator', 'applications/base/controller/base');
|
||||
phutil_require_module('phabricator', 'infrastructure/env');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorSlowvoteController.php');
|
|
@ -0,0 +1,160 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class PhabricatorSlowvoteCreateController
|
||||
extends PhabricatorSlowvoteController {
|
||||
|
||||
public function processRequest() {
|
||||
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$poll = new PhabricatorSlowvotePoll();
|
||||
$poll->setAuthorPHID($user->getPHID());
|
||||
|
||||
$e_question = true;
|
||||
$e_response = true;
|
||||
$errors = array();
|
||||
|
||||
$responses = $request->getArr('response');
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$poll->setQuestion($request->getStr('question'));
|
||||
$poll->setResponseVisibility($request->getInt('response_visibility'));
|
||||
$poll->setShuffle($request->getBool('shuffle', false));
|
||||
$poll->setMethod($request->getInt('method'));
|
||||
|
||||
if (!strlen($poll->getQuestion())) {
|
||||
$e_question = 'Required';
|
||||
$errors[] = 'You must ask a poll question.';
|
||||
} else {
|
||||
$e_question = null;
|
||||
}
|
||||
|
||||
$responses = array_filter($responses);
|
||||
if (empty($responses)) {
|
||||
$errors[] = 'You must offer at least one response.';
|
||||
$e_response = 'Required';
|
||||
} else {
|
||||
$e_response = null;
|
||||
}
|
||||
|
||||
if (empty($errors)) {
|
||||
$poll->save();
|
||||
|
||||
foreach ($responses as $response) {
|
||||
$option = new PhabricatorSlowvoteOption();
|
||||
$option->setName($response);
|
||||
$option->setPollID($poll->getID());
|
||||
$option->save();
|
||||
}
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/V'.$poll->getID());
|
||||
}
|
||||
}
|
||||
|
||||
$error_view = null;
|
||||
if ($errors) {
|
||||
$error_view = new AphrontErrorView();
|
||||
$error_view->setTitle('Form Errors');
|
||||
$error_view->setErrors($errors);
|
||||
}
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($user)
|
||||
->appendChild(
|
||||
'<p class="aphront-form-instructions">Resolve issues and build '.
|
||||
'consensus through protracted deliberation.</p>')
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel('Question')
|
||||
->setName('question')
|
||||
->setValue($poll->getQuestion())
|
||||
->setError($e_question));
|
||||
|
||||
for ($ii = 0; $ii < 10; $ii++) {
|
||||
$n = ($ii + 1);
|
||||
$response = id(new AphrontFormTextControl())
|
||||
->setLabel("Response {$n}")
|
||||
->setName('response[]')
|
||||
->setValue(idx($responses, $ii, ''));
|
||||
|
||||
if ($ii == 0) {
|
||||
$response->setError($e_response);
|
||||
}
|
||||
|
||||
$form->appendChild($response);
|
||||
}
|
||||
|
||||
$poll_type_options = array(
|
||||
PhabricatorSlowvotePoll::METHOD_PLURALITY => 'Plurality (Single Choice)',
|
||||
PhabricatorSlowvotePoll::METHOD_APPROVAL => 'Approval (Multiple Choice)',
|
||||
);
|
||||
|
||||
$response_type_options = array(
|
||||
PhabricatorSlowvotePoll::RESPONSES_VISIBLE
|
||||
=> 'Allow anyone to see the responses',
|
||||
PhabricatorSlowvotePoll::RESPONSES_VOTERS
|
||||
=> 'Require a vote to see the responses',
|
||||
PhabricatorSlowvotePoll::RESPONSES_OWNER
|
||||
=> 'Only I can see the responses',
|
||||
);
|
||||
|
||||
$form
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setLabel('Vote Type')
|
||||
->setName('method')
|
||||
->setValue($poll->getMethod())
|
||||
->setOptions($poll_type_options))
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setLabel('Responses')
|
||||
->setName('response_visibility')
|
||||
->setValue($poll->getResponseVisibility())
|
||||
->setOptions($response_type_options))
|
||||
->appendChild(
|
||||
id(new AphrontFormCheckboxControl())
|
||||
->setLabel('Shuffle')
|
||||
->addCheckbox(
|
||||
'shuffle',
|
||||
1,
|
||||
'Show choices in random order',
|
||||
$poll->getShuffle()))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue('Create Slowvote')
|
||||
->addCancelButton('/vote/'));
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
|
||||
$panel->setHeader('Create Slowvote');
|
||||
$panel->appendChild($form);
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
array(
|
||||
$error_view,
|
||||
$panel,
|
||||
),
|
||||
array(
|
||||
'title' => 'Create Slowvote',
|
||||
));
|
||||
}
|
||||
|
||||
}
|
24
src/applications/slowvote/controller/create/__init__.php
Normal file
24
src/applications/slowvote/controller/create/__init__.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/response/redirect');
|
||||
phutil_require_module('phabricator', 'applications/slowvote/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/slowvote/storage/option');
|
||||
phutil_require_module('phabricator', 'applications/slowvote/storage/poll');
|
||||
phutil_require_module('phabricator', 'view/form/base');
|
||||
phutil_require_module('phabricator', 'view/form/control/checkbox');
|
||||
phutil_require_module('phabricator', 'view/form/control/select');
|
||||
phutil_require_module('phabricator', 'view/form/control/submit');
|
||||
phutil_require_module('phabricator', 'view/form/control/text');
|
||||
phutil_require_module('phabricator', 'view/form/error');
|
||||
phutil_require_module('phabricator', 'view/layout/panel');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorSlowvoteCreateController.php');
|
|
@ -0,0 +1,167 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class PhabricatorSlowvoteListController
|
||||
extends PhabricatorSlowvoteController {
|
||||
|
||||
private $view;
|
||||
|
||||
const VIEW_ALL = 'all';
|
||||
const VIEW_CREATED = 'created';
|
||||
const VIEW_VOTED = 'voted';
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->view = idx($data, 'view');
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$filters = array(
|
||||
self::VIEW_ALL => 'All Slowvotes',
|
||||
self::VIEW_CREATED => 'Created',
|
||||
self::VIEW_VOTED => 'Voted In',
|
||||
);
|
||||
|
||||
$view = isset($filters[$this->view])
|
||||
? $this->view
|
||||
: self::VIEW_ALL;
|
||||
|
||||
$side_nav = new AphrontSideNavView();
|
||||
foreach ($filters as $key => $name) {
|
||||
$side_nav->addNavItem(
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/vote/view/'.$key.'/',
|
||||
'class' => ($view == $key) ? 'aphront-side-nav-selected' : null,
|
||||
),
|
||||
phutil_escape_html($name)));
|
||||
}
|
||||
|
||||
|
||||
$poll = new PhabricatorSlowvotePoll();
|
||||
$conn = $poll->establishConnection('r');
|
||||
|
||||
$pager = new AphrontPagerView();
|
||||
$pager->setOffset($request->getInt('page'));
|
||||
$pager->setURI($request->getRequestURI(), 'page');
|
||||
$offset = $pager->getOffset();
|
||||
$limit = $pager->getPageSize() + 1;
|
||||
|
||||
switch ($view) {
|
||||
case self::VIEW_ALL:
|
||||
$data = queryfx_all(
|
||||
$conn,
|
||||
'SELECT * FROM %T ORDER BY id DESC LIMIT %d, %d',
|
||||
$poll->getTableName(),
|
||||
$offset,
|
||||
$limit);
|
||||
break;
|
||||
case self::VIEW_CREATED:
|
||||
$data = queryfx_all(
|
||||
$conn,
|
||||
'SELECT * FROM %T WHERE authorPHID = %s ORDER BY id DESC
|
||||
LIMIT %d, %d',
|
||||
$poll->getTableName(),
|
||||
$user->getPHID(),
|
||||
$offset,
|
||||
$limit);
|
||||
break;
|
||||
case self::VIEW_VOTED:
|
||||
$choice = new PhabricatorSlowvoteChoice();
|
||||
$data = queryfx_all(
|
||||
$conn,
|
||||
'SELECT p.* FROM %T p JOIN %T o
|
||||
ON o.pollID = p.id
|
||||
WHERE o.authorPHID = %s
|
||||
GROUP BY p.id
|
||||
ORDER BY p.id DESC
|
||||
LIMIT %d, %d',
|
||||
$poll->getTableName(),
|
||||
$choice->getTableName(),
|
||||
$user->getPHID(),
|
||||
$offset,
|
||||
$limit);
|
||||
break;
|
||||
}
|
||||
|
||||
$data = $pager->sliceResults($data);
|
||||
$polls = $poll->loadAllFromArray($data);
|
||||
|
||||
$phids = mpull($polls, 'getAuthorPHID');
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
|
||||
|
||||
$rows = array();
|
||||
foreach ($polls as $poll) {
|
||||
$rows[] = array(
|
||||
$handles[$poll->getAuthorPHID()]->renderLink(),
|
||||
phutil_render_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => '/V'.$poll->getID(),
|
||||
),
|
||||
phutil_escape_html('V'.$poll->getID().' '.$poll->getQuestion())),
|
||||
phabricator_date($poll->getDateCreated(), $user),
|
||||
phabricator_time($poll->getDateCreated(), $user),
|
||||
);
|
||||
}
|
||||
|
||||
$table = new AphrontTableView($rows);
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
'',
|
||||
'pri wide',
|
||||
'',
|
||||
'right',
|
||||
));
|
||||
$table->setHeaders(
|
||||
array(
|
||||
'Author',
|
||||
'Poll',
|
||||
'Date',
|
||||
'Time',
|
||||
));
|
||||
|
||||
$headers = array(
|
||||
self::VIEW_ALL
|
||||
=> 'Slowvotes Not Yet Consumed by the Ravages of Time',
|
||||
self::VIEW_CREATED
|
||||
=> 'Slowvotes Birthed from Your Noblest of Great Minds',
|
||||
self::VIEW_VOTED
|
||||
=> 'Slowvotes Within Which You Express Your Mighty Opinion',
|
||||
);
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader(idx($headers, $view));
|
||||
$panel->setCreateButton('Create Slowvote', '/vote/create/');
|
||||
$panel->appendChild($table);
|
||||
$panel->appendChild($pager);
|
||||
|
||||
$side_nav->appendChild($panel);
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
$side_nav,
|
||||
array(
|
||||
'title' => 'Slowvotes',
|
||||
));
|
||||
}
|
||||
|
||||
}
|
24
src/applications/slowvote/controller/list/__init__.php
Normal file
24
src/applications/slowvote/controller/list/__init__.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'applications/slowvote/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/slowvote/storage/choice');
|
||||
phutil_require_module('phabricator', 'applications/slowvote/storage/poll');
|
||||
phutil_require_module('phabricator', 'storage/queryfx');
|
||||
phutil_require_module('phabricator', 'view/control/pager');
|
||||
phutil_require_module('phabricator', 'view/control/table');
|
||||
phutil_require_module('phabricator', 'view/layout/panel');
|
||||
phutil_require_module('phabricator', 'view/layout/sidenav');
|
||||
phutil_require_module('phabricator', 'view/utils');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorSlowvoteListController.php');
|
|
@ -0,0 +1,390 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class PhabricatorSlowvotePollController
|
||||
extends PhabricatorSlowvoteController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$viewer_phid = $user->getPHID();
|
||||
|
||||
$poll = id(new PhabricatorSlowvotePoll())->load($this->id);
|
||||
if (!$poll) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$options = id(new PhabricatorSlowvoteOption())->loadAllWhere(
|
||||
'pollID = %d',
|
||||
$poll->getID());
|
||||
$choices = id(new PhabricatorSlowvoteChoice())->loadAllWhere(
|
||||
'pollID = %d',
|
||||
$poll->getID());
|
||||
$comments = id(new PhabricatorSlowvoteComment())->loadAllWhere(
|
||||
'pollID = %d',
|
||||
$poll->getID());
|
||||
|
||||
switch ($poll->getMethod()) {
|
||||
case PhabricatorSlowvotePoll::METHOD_PLURALITY:
|
||||
$out_of_total = count($choices);
|
||||
break;
|
||||
case PhabricatorSlowvotePoll::METHOD_APPROVAL:
|
||||
// Count unique respondents for approval votes.
|
||||
$out_of_total = count(mpull($choices, null, 'getAuthorPHID'));
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unknown poll method!");
|
||||
}
|
||||
|
||||
$choices_by_option = mgroup($choices, 'getOptionID');
|
||||
$comments_by_user = mpull($comments, null, 'getAuthorPHID');
|
||||
$choices_by_user = mgroup($choices, 'getAuthorPHID');
|
||||
$viewer_choices = idx($choices_by_user, $viewer_phid, array());
|
||||
$viewer_comment = idx($comments_by_user, $viewer_phid, null);
|
||||
|
||||
$comment_text = null;
|
||||
if ($viewer_comment) {
|
||||
$comment_text = $viewer_comment->getCommentText();
|
||||
}
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$comment = idx($comments_by_user, $viewer_phid, null);
|
||||
if ($comment) {
|
||||
$comment->delete();
|
||||
}
|
||||
|
||||
$comment_text = $request->getStr('comments');
|
||||
if (strlen($comment_text)) {
|
||||
id(new PhabricatorSlowvoteComment())
|
||||
->setAuthorPHID($viewer_phid)
|
||||
->setPollID($poll->getID())
|
||||
->setCommentText($comment_text)
|
||||
->save();
|
||||
}
|
||||
|
||||
$votes = $request->getArr('vote');
|
||||
|
||||
switch ($poll->getMethod()) {
|
||||
case PhabricatorSlowvotePoll::METHOD_PLURALITY:
|
||||
// Enforce only one vote.
|
||||
$votes = array_slice($votes, 0, 1);
|
||||
break;
|
||||
case PhabricatorSlowvotePoll::METHOD_APPROVAL:
|
||||
// No filtering.
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unknown poll method!");
|
||||
}
|
||||
|
||||
foreach ($viewer_choices as $viewer_choice) {
|
||||
$viewer_choice->delete();
|
||||
}
|
||||
|
||||
foreach ($votes as $vote) {
|
||||
id(new PhabricatorSlowvoteChoice())
|
||||
->setAuthorPHID($viewer_phid)
|
||||
->setPollID($poll->getID())
|
||||
->setOptionID($vote)
|
||||
->save();
|
||||
}
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI('/V'.$poll->getID());
|
||||
}
|
||||
|
||||
require_celerity_resource('phabricator-slowvote-css');
|
||||
|
||||
$phids = array_merge(
|
||||
mpull($choices, 'getAuthorPHID'),
|
||||
mpull($comments, 'getAuthorPHID'),
|
||||
array(
|
||||
$poll->getAuthorPHID(),
|
||||
));
|
||||
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
|
||||
|
||||
if ($poll->getShuffle()) {
|
||||
shuffle($options);
|
||||
}
|
||||
|
||||
$option_markup = array();
|
||||
foreach ($options as $option) {
|
||||
$id = $option->getID();
|
||||
switch ($poll->getMethod()) {
|
||||
case PhabricatorSlowvotePoll::METHOD_PLURALITY:
|
||||
|
||||
// Render a radio button.
|
||||
|
||||
$selected_option = head($viewer_choices);
|
||||
if ($selected_option) {
|
||||
$selected = $selected_option->getOptionID();
|
||||
} else {
|
||||
$selected = null;
|
||||
}
|
||||
|
||||
if ($selected == $id) {
|
||||
$checked = "checked";
|
||||
} else {
|
||||
$checked = null;
|
||||
}
|
||||
|
||||
$input = phutil_render_tag(
|
||||
'input',
|
||||
array(
|
||||
'type' => 'radio',
|
||||
'name' => 'vote[]',
|
||||
'value' => $id,
|
||||
'checked' => $checked,
|
||||
));
|
||||
break;
|
||||
case PhabricatorSlowvotePoll::METHOD_APPROVAL:
|
||||
|
||||
// Render a check box.
|
||||
|
||||
$checked = null;
|
||||
foreach ($viewer_choices as $choice) {
|
||||
if ($choice->getOptionID() == $id) {
|
||||
$checked = 'checked';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$input = phutil_render_tag(
|
||||
'input',
|
||||
array(
|
||||
'type' => 'checkbox',
|
||||
'name' => 'vote[]',
|
||||
'checked' => $checked,
|
||||
'value' => $id,
|
||||
));
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unknown poll method!");
|
||||
}
|
||||
|
||||
if ($checked) {
|
||||
$checked_class = 'phabricator-slowvote-checked';
|
||||
} else {
|
||||
$checked_class = null;
|
||||
}
|
||||
|
||||
$option_markup[] = phutil_render_tag(
|
||||
'label',
|
||||
array(
|
||||
'class' => 'phabricator-slowvote-label '.$checked_class,
|
||||
),
|
||||
$input.phutil_escape_html($option->getName()));
|
||||
}
|
||||
$option_markup = implode("\n", $option_markup);
|
||||
|
||||
$comments_by_option = array();
|
||||
switch ($poll->getMethod()) {
|
||||
case PhabricatorSlowvotePoll::METHOD_PLURALITY:
|
||||
$choice_ids = array();
|
||||
foreach ($choices_by_user as $user_phid => $choices) {
|
||||
$choice_ids[$user_phid] = head($choices)->getOptionID();
|
||||
}
|
||||
foreach ($comments as $comment) {
|
||||
$choice = idx($choice_ids, $comment->getAuthorPHID());
|
||||
if ($choice) {
|
||||
$comments_by_option[$choice][] = $comment;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PhabricatorSlowvotePoll::METHOD_APPROVAL:
|
||||
// All comments are grouped in approval voting.
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unknown poll method!");
|
||||
}
|
||||
|
||||
$can_see_responses = false;
|
||||
$need_vote = false;
|
||||
switch ($poll->getResponseVisibility()) {
|
||||
case PhabricatorSlowvotePoll::RESPONSES_VISIBLE:
|
||||
$can_see_responses = true;
|
||||
break;
|
||||
case PhabricatorSlowvotePoll::RESPONSES_VOTERS:
|
||||
$can_see_responses = (bool)$viewer_choices;
|
||||
$need_vote = true;
|
||||
break;
|
||||
case PhabricatorSlowvotePoll::RESPONSES_OWNER:
|
||||
$can_see_responses = ($viewer_phid == $poll->getAuthorPHID());
|
||||
break;
|
||||
}
|
||||
|
||||
$result_markup = id(new AphrontFormLayoutView())
|
||||
->appendChild('<h1>Ongoing Deliberation</h1>');
|
||||
|
||||
if (!$can_see_responses) {
|
||||
if ($need_vote) {
|
||||
$reason = "You must vote to see the results.";
|
||||
} else {
|
||||
$reason = "The results are not public.";
|
||||
}
|
||||
$result_markup
|
||||
->appendChild(
|
||||
'<p class="aphront-form-instructions"><em>'.$reason.'</em></p>');
|
||||
} else {
|
||||
foreach ($options as $option) {
|
||||
$id = $option->getID();
|
||||
|
||||
$chosen = idx($choices_by_option, $id, array());
|
||||
$users = array_select_keys($handles, mpull($chosen, 'getAuthorPHID'));
|
||||
if ($users) {
|
||||
$user_markup = array();
|
||||
foreach ($users as $handle) {
|
||||
$user_markup[] = $handle->renderLink();
|
||||
}
|
||||
$user_markup = implode('', $user_markup);
|
||||
} else {
|
||||
$user_markup = 'This option has failed to appeal to anyone.';
|
||||
}
|
||||
|
||||
$comment_markup = $this->renderComments(
|
||||
idx($comments_by_option, $id, array()),
|
||||
$handles);
|
||||
|
||||
$display = sprintf(
|
||||
'%d / %d (%d%%)',
|
||||
number_format(count($chosen)),
|
||||
number_format($out_of_total),
|
||||
$out_of_total
|
||||
? round(100 * count($chosen) / $out_of_total)
|
||||
: 0);
|
||||
|
||||
$result_markup->appendChild(
|
||||
'<div>'.
|
||||
'<div class="phabricator-slowvote-count">'.
|
||||
$display.
|
||||
'</div>'.
|
||||
'<h1>'.phutil_escape_html($option->getName()).'</h1>'.
|
||||
'<hr class="phabricator-slowvote-hr" />'.
|
||||
$user_markup.
|
||||
'<hr class="phabricator-slowvote-hr" />'.
|
||||
$comment_markup.
|
||||
'</div>');
|
||||
}
|
||||
|
||||
if ($poll->getMethod() == PhabricatorSlowvotePoll::METHOD_APPROVAL &&
|
||||
$comments) {
|
||||
$comment_markup = $this->renderComments(
|
||||
$comments,
|
||||
$handles);
|
||||
$result_markup->appendChild(
|
||||
'<h1>Motions Proposed for Consideration</h1>');
|
||||
$result_markup->appendChild($comment_markup);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($viewer_choices) {
|
||||
$instructions =
|
||||
'Your vote has been recorded... but there is still ample time to '.
|
||||
'rethink your position. Have you thoroughly considered all possible '.
|
||||
'eventualities?';
|
||||
} else {
|
||||
$instructions =
|
||||
'This is a weighty matter indeed. Consider your choices with the '.
|
||||
'greatest of care.';
|
||||
}
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($user)
|
||||
->appendChild(
|
||||
'<p class="aphront-form-instructions">'.$instructions.'</p>')
|
||||
->appendChild(
|
||||
id(new AphrontFormMarkupControl())
|
||||
->setLabel('Vote')
|
||||
->setValue($option_markup))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextAreaControl())
|
||||
->setLabel('Comments')
|
||||
->setHeight(AphrontFormTextAreaControl::HEIGHT_SHORT)
|
||||
->setName('comments')
|
||||
->setValue($comment_text))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue('Cautiously Engage in Deliberations'));
|
||||
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader(phutil_escape_html($poll->getQuestion()));
|
||||
$panel->setWidth(AphrontPanelView::WIDTH_WIDE);
|
||||
|
||||
$panel->appendChild($form);
|
||||
$panel->appendChild('<br /><br />');
|
||||
$panel->appendChild($result_markup);
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
$panel,
|
||||
array(
|
||||
'title' => 'V'.$poll->getID().' '.$poll->getQuestion(),
|
||||
));
|
||||
}
|
||||
|
||||
private function renderComments(array $comments, array $handles) {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$factory = new DifferentialMarkupEngineFactory();
|
||||
$engine = $factory->newDifferentialCommentMarkupEngine();
|
||||
|
||||
$comment_markup = array();
|
||||
foreach ($comments as $comment) {
|
||||
$handle = $handles[$comment->getAuthorPHID()];
|
||||
|
||||
$markup = $engine->markupText($comment->getCommentText());
|
||||
|
||||
require_celerity_resource('phabricator-remarkup-css');
|
||||
|
||||
$comment_markup[] =
|
||||
'<tr>'.
|
||||
'<th>'.
|
||||
$handle->renderLink().
|
||||
'<div class="phabricator-slowvote-datestamp">'.
|
||||
phabricator_datetime($comment->getDateCreated(), $viewer).
|
||||
'</div>'.
|
||||
'<td>'.
|
||||
'<div class="phabricator-remarkup">'.
|
||||
$markup.
|
||||
'</div>'.
|
||||
'</td>'.
|
||||
'</tr>';
|
||||
}
|
||||
|
||||
if ($comment_markup) {
|
||||
$comment_markup = phutil_render_tag(
|
||||
'table',
|
||||
array(
|
||||
'class' => 'phabricator-slowvote-comments',
|
||||
),
|
||||
implode("\n", $comment_markup));
|
||||
} else {
|
||||
$comment_markup = null;
|
||||
}
|
||||
|
||||
return $comment_markup;
|
||||
}
|
||||
|
||||
}
|
31
src/applications/slowvote/controller/poll/__init__.php
Normal file
31
src/applications/slowvote/controller/poll/__init__.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/response/404');
|
||||
phutil_require_module('phabricator', 'aphront/response/redirect');
|
||||
phutil_require_module('phabricator', 'applications/differential/parser/markup');
|
||||
phutil_require_module('phabricator', 'applications/phid/handle/data');
|
||||
phutil_require_module('phabricator', 'applications/slowvote/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/slowvote/storage/choice');
|
||||
phutil_require_module('phabricator', 'applications/slowvote/storage/comment');
|
||||
phutil_require_module('phabricator', 'applications/slowvote/storage/option');
|
||||
phutil_require_module('phabricator', 'applications/slowvote/storage/poll');
|
||||
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
||||
phutil_require_module('phabricator', 'view/form/base');
|
||||
phutil_require_module('phabricator', 'view/form/control/markup');
|
||||
phutil_require_module('phabricator', 'view/form/control/submit');
|
||||
phutil_require_module('phabricator', 'view/form/control/textarea');
|
||||
phutil_require_module('phabricator', 'view/form/layout');
|
||||
phutil_require_module('phabricator', 'view/layout/panel');
|
||||
phutil_require_module('phabricator', 'view/utils');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorSlowvotePollController.php');
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class PhabricatorSlowvoteDAO extends PhabricatorLiskDAO {
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'slowvote';
|
||||
}
|
||||
|
||||
}
|
12
src/applications/slowvote/storage/base/__init__.php
Normal file
12
src/applications/slowvote/storage/base/__init__.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/base/storage/lisk');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorSlowvoteDAO.php');
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class PhabricatorSlowvoteChoice extends PhabricatorSlowvoteDAO {
|
||||
|
||||
protected $pollID;
|
||||
protected $optionID;
|
||||
protected $authorPHID;
|
||||
|
||||
}
|
12
src/applications/slowvote/storage/choice/__init__.php
Normal file
12
src/applications/slowvote/storage/choice/__init__.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/slowvote/storage/base');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorSlowvoteChoice.php');
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class PhabricatorSlowvoteComment extends PhabricatorSlowvoteDAO {
|
||||
|
||||
protected $pollID;
|
||||
protected $authorPHID;
|
||||
protected $commentText;
|
||||
|
||||
}
|
12
src/applications/slowvote/storage/comment/__init__.php
Normal file
12
src/applications/slowvote/storage/comment/__init__.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/slowvote/storage/base');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorSlowvoteComment.php');
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class PhabricatorSlowvoteOption extends PhabricatorSlowvoteDAO {
|
||||
|
||||
protected $pollID;
|
||||
protected $name;
|
||||
|
||||
|
||||
}
|
12
src/applications/slowvote/storage/option/__init__.php
Normal file
12
src/applications/slowvote/storage/option/__init__.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/slowvote/storage/base');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorSlowvoteOption.php');
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class PhabricatorSlowvotePoll extends PhabricatorSlowvoteDAO {
|
||||
|
||||
const RESPONSES_VISIBLE = 0;
|
||||
const RESPONSES_VOTERS = 1;
|
||||
const RESPONSES_OWNER = 2;
|
||||
|
||||
const METHOD_PLURALITY = 0;
|
||||
const METHOD_APPROVAL = 1;
|
||||
|
||||
protected $question;
|
||||
protected $phid;
|
||||
protected $authorPHID;
|
||||
protected $responseVisibility;
|
||||
protected $shuffle;
|
||||
protected $method;
|
||||
|
||||
public function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_AUX_PHID => true,
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public function generatePHID() {
|
||||
return PhabricatorPHID::generateNewPHID(
|
||||
PhabricatorPHIDConstants::PHID_TYPE_POLL);
|
||||
}
|
||||
|
||||
}
|
14
src/applications/slowvote/storage/poll/__init__.php
Normal file
14
src/applications/slowvote/storage/poll/__init__.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/phid/constants');
|
||||
phutil_require_module('phabricator', 'applications/phid/storage/phid');
|
||||
phutil_require_module('phabricator', 'applications/slowvote/storage/base');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorSlowvotePoll.php');
|
27
src/docs/userguide/slowvote.diviner
Normal file
27
src/docs/userguide/slowvote.diviner
Normal file
|
@ -0,0 +1,27 @@
|
|||
@title Slowvote User Guide
|
||||
@group userguide
|
||||
|
||||
Detailed dispute resolution manual.
|
||||
|
||||
= Overview =
|
||||
|
||||
Slowvote is a simple polling application for asking questions like "Where should
|
||||
we order pizza from?", "Are dogs better than cats?" and "What is the optimal
|
||||
strategic direction for our company?". You can use it to quickly get feedback
|
||||
from people in a lightweight, structured way.
|
||||
|
||||
Slowvote is based on a Facebook application called Quickvote, which was pretty
|
||||
good when it was originally written but went through a couple of poorly executed
|
||||
rewrites and ended up being extremely slow and glitchy, often taking more than
|
||||
10 seconds to load. I originally designed and implemented the entire Slowvote
|
||||
application while waiting for a Quikvote to load.
|
||||
|
||||
= Plurality vs Approval =
|
||||
|
||||
When you create a poll, you can choose **plurality** or **approval** voting.
|
||||
|
||||
In plurality voting, users choose one option. The winning option is the one with
|
||||
the most votes.
|
||||
|
||||
In approval voting, users choose all the options they approve of. The winning
|
||||
option is the one the largest number of people accept.
|
60
webroot/rsrc/css/application/slowvote/slowvote.css
Normal file
60
webroot/rsrc/css/application/slowvote/slowvote.css
Normal file
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* @provides phabricator-slowvote-css
|
||||
*/
|
||||
|
||||
.phabricator-slowvote-comments {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.phabricator-slowvote-comments th {
|
||||
width: 150px;
|
||||
text-align: right;
|
||||
padding: 6px 4px 6px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.phabricator-slowvote-comments td {
|
||||
vertical-align: top;
|
||||
padding: 6px 2px;
|
||||
border-bottom: 1px solid #d0d0d0;
|
||||
}
|
||||
|
||||
.phabricator-slowvote-datestamp {
|
||||
font-size: 9px;
|
||||
font-family: "Verdana";
|
||||
color: #666666;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.phabricator-slowvote-hr {
|
||||
border: none;
|
||||
height: 1px;
|
||||
position: relative;
|
||||
background: #c0c0c0;
|
||||
}
|
||||
|
||||
.phabricator-slowvote-count {
|
||||
float: right;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.phabricator-slowvote-label {
|
||||
display: block;
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #222222;
|
||||
text-align: left;
|
||||
margin: 0px 0px 6px;
|
||||
padding: 6px 4px;
|
||||
background: #cccccc;
|
||||
border-bottom: 1px solid #aaaaaa;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.aphront-form-input .phabricator-slowvote-label input {
|
||||
display: inline;
|
||||
width: auto;
|
||||
margin-right: 12px;
|
||||
}
|
Loading…
Reference in a new issue