2011-06-10 08:53:53 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/*
|
2012-01-10 23:48:55 +01:00
|
|
|
* Copyright 2012 Facebook, Inc.
|
2011-06-10 08:53:53 +02:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2012-03-10 00:46:25 +01:00
|
|
|
final class PhabricatorPasteViewController extends PhabricatorPasteController {
|
2011-06-10 08:53:53 +02:00
|
|
|
|
|
|
|
private $id;
|
|
|
|
|
|
|
|
public function willProcessRequest(array $data) {
|
|
|
|
$this->id = $data['id'];
|
|
|
|
}
|
|
|
|
|
|
|
|
public function processRequest() {
|
|
|
|
|
|
|
|
$request = $this->getRequest();
|
|
|
|
$user = $request->getUser();
|
|
|
|
|
Add basic per-object privacy policies
Summary:
Provides a basic start for access policies. Objects expose various capabilities, like CAN_VIEW, CAN_EDIT, etc., and set a policy for each capability. We currently implement three policies, PUBLIC (anyone, including logged-out), USERS (any logged-in) and NOONE (nobody). There's also a way to provide automatic capability grants (e.g., the owner of an object can always see it, even if some capability is set to "NOONE"), but I'm not sure how great the implementation feels and it might change.
Most of the code here is providing a primitive for efficient policy-aware list queries. The problem with doing queries naively is that you have to do crazy amounts of filtering, e.g. to show the user page 6, you need to filter at least 600 objects (and likely more) before you can figure out which ones are 500-600 for them. You can't just do "LIMIT 500, 100" because that might have only 50 results, or no results. Instead, the query looks like "WHERE id > last_visible_id", and then we fetch additional pages as necessary to satisfy the request.
The general idea is that we move all data access to Query classes and have them do object filtering. The ID paging primitive allows efficient paging in most cases, and the executeOne() method provides a concise way to do policy checks for edit/view screens.
We'll probably end up with mostly broader policy UIs or configuration-based policies, but there are at least a few cases for per-object privacy (e.g., marking tasks as "Security", and restricting things to the members of projects) so I figured we'd start with a flexible primitive and the simplify it in the UI where we can.
Test Plan: Unit tests, played around in the UI with various policy settings.
Reviewers: btrahan, vrana, jungejason
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T603
Differential Revision: https://secure.phabricator.com/D2210
2012-04-14 19:13:29 +02:00
|
|
|
$paste = id(new PhabricatorPasteQuery())
|
|
|
|
->setViewer($user)
|
|
|
|
->withPasteIDs(array($this->id))
|
|
|
|
->executeOne();
|
|
|
|
|
2011-06-10 08:53:53 +02:00
|
|
|
if (!$paste) {
|
|
|
|
return new Aphront404Response();
|
|
|
|
}
|
|
|
|
|
|
|
|
$file = id(new PhabricatorFile())->loadOneWhere(
|
|
|
|
'phid = %s',
|
|
|
|
$paste->getFilePHID());
|
|
|
|
if (!$file) {
|
|
|
|
return new Aphront400Response();
|
|
|
|
}
|
|
|
|
|
|
|
|
$corpus = $this->buildCorpus($paste, $file);
|
2011-07-21 08:17:30 +02:00
|
|
|
$paste_panel = new AphrontPanelView();
|
2011-06-10 08:53:53 +02:00
|
|
|
|
|
|
|
if (strlen($paste->getTitle())) {
|
2011-07-21 08:17:30 +02:00
|
|
|
$paste_panel->setHeader(
|
2011-06-10 08:53:53 +02:00
|
|
|
'Viewing Paste '.$paste->getID().' - '.
|
|
|
|
phutil_escape_html($paste->getTitle()));
|
|
|
|
} else {
|
2011-07-21 08:17:30 +02:00
|
|
|
$paste_panel->setHeader('Viewing Paste '.$paste->getID());
|
2011-06-10 08:53:53 +02:00
|
|
|
}
|
|
|
|
|
2011-07-21 08:17:30 +02:00
|
|
|
$paste_panel->setWidth(AphrontPanelView::WIDTH_FULL);
|
|
|
|
$paste_panel->addButton(
|
2011-06-14 04:12:30 +02:00
|
|
|
phutil_render_tag(
|
|
|
|
'a',
|
|
|
|
array(
|
2011-07-15 22:49:45 +02:00
|
|
|
'href' => '/paste/?fork='.$paste->getID(),
|
2011-06-14 04:12:30 +02:00
|
|
|
'class' => 'green button',
|
|
|
|
),
|
2011-07-15 22:49:45 +02:00
|
|
|
'Fork This'));
|
2011-06-14 04:12:30 +02:00
|
|
|
|
2012-01-10 23:48:55 +01:00
|
|
|
$raw_uri = $file->getBestURI();
|
2011-07-21 08:17:30 +02:00
|
|
|
$paste_panel->addButton(
|
2011-06-14 04:12:30 +02:00
|
|
|
phutil_render_tag(
|
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'href' => $raw_uri,
|
|
|
|
'class' => 'button',
|
|
|
|
),
|
|
|
|
'View Raw Text'));
|
|
|
|
|
2011-07-21 08:17:30 +02:00
|
|
|
$paste_panel->appendChild($corpus);
|
2011-06-10 08:53:53 +02:00
|
|
|
|
2011-07-21 08:17:30 +02:00
|
|
|
$forks_panel = null;
|
2011-07-15 22:49:45 +02:00
|
|
|
$forks_of_this_paste = id(new PhabricatorPaste())->loadAllWhere(
|
|
|
|
'parentPHID = %s',
|
|
|
|
$paste->getPHID());
|
|
|
|
|
|
|
|
if ($forks_of_this_paste) {
|
2011-07-21 08:17:30 +02:00
|
|
|
$forks_panel = new AphrontPanelView();
|
|
|
|
$forks_panel->setHeader("Forks of this paste");
|
2011-07-15 22:49:45 +02:00
|
|
|
$forks = array();
|
|
|
|
foreach ($forks_of_this_paste as $fork) {
|
|
|
|
$forks[] = array(
|
|
|
|
$fork->getID(),
|
|
|
|
phutil_render_tag(
|
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'href' => '/P'.$fork->getID(),
|
|
|
|
),
|
|
|
|
phutil_escape_html($fork->getTitle())
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
$forks_table = new AphrontTableView($forks);
|
|
|
|
$forks_table->setHeaders(
|
|
|
|
array(
|
|
|
|
'Paste ID',
|
|
|
|
'Title',
|
|
|
|
)
|
|
|
|
);
|
2011-07-21 08:17:30 +02:00
|
|
|
$forks_table->setColumnClasses(
|
|
|
|
array(
|
|
|
|
null,
|
|
|
|
'wide pri',
|
|
|
|
)
|
|
|
|
);
|
|
|
|
$forks_panel->appendChild($forks_table);
|
2011-07-15 22:49:45 +02:00
|
|
|
}
|
|
|
|
|
2011-06-10 08:53:53 +02:00
|
|
|
return $this->buildStandardPageResponse(
|
2011-07-21 08:17:30 +02:00
|
|
|
array(
|
|
|
|
$paste_panel,
|
|
|
|
$forks_panel,
|
|
|
|
),
|
2011-06-10 08:53:53 +02:00
|
|
|
array(
|
2011-06-14 04:12:30 +02:00
|
|
|
'title' => 'Paste: '.nonempty($paste->getTitle(), 'P'.$paste->getID()),
|
2011-06-10 08:53:53 +02:00
|
|
|
'tab' => 'view',
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildCorpus($paste, $file) {
|
|
|
|
// Blantently copied from DiffusionBrowseFileController
|
|
|
|
|
|
|
|
require_celerity_resource('diffusion-source-css');
|
|
|
|
require_celerity_resource('syntax-highlighting-css');
|
|
|
|
|
2011-07-06 20:10:40 +02:00
|
|
|
$language = $paste->getLanguage();
|
2011-07-06 21:12:17 +02:00
|
|
|
$source = $file->loadFileData();
|
2011-07-06 20:10:40 +02:00
|
|
|
if (empty($language)) {
|
2011-07-06 21:12:17 +02:00
|
|
|
$source = PhabricatorSyntaxHighlighter::highlightWithFilename(
|
|
|
|
$paste->getTitle(),
|
|
|
|
$source);
|
|
|
|
} else {
|
|
|
|
$source = PhabricatorSyntaxHighlighter::highlightWithLanguage(
|
|
|
|
$language,
|
|
|
|
$source);
|
2011-07-06 20:10:40 +02:00
|
|
|
}
|
|
|
|
|
2011-07-06 21:12:17 +02:00
|
|
|
$text_list = explode("\n", $source);
|
2011-06-10 08:53:53 +02:00
|
|
|
|
Kind-of-terrible (?) oncopy handler
Summary: Works in Safari, Firefox, Chrome.
Test Plan: Copied some text, threw up a little in my mouth.
Reviewers: aran, tuomaspelkonen, tomo, rstout, btrahan
Reviewed By: aran
CC: aran, epriestley, ddfisher
Maniphest Tasks: T145, T995
Differential Revision: https://secure.phabricator.com/D244
2012-03-16 03:04:59 +01:00
|
|
|
Javelin::initBehavior('phabricator-oncopy', array());
|
2011-06-10 08:53:53 +02:00
|
|
|
$rows = $this->buildDisplayRows($text_list);
|
|
|
|
|
|
|
|
$corpus_table = phutil_render_tag(
|
|
|
|
'table',
|
|
|
|
array(
|
2011-06-15 10:52:40 +02:00
|
|
|
'class' => 'diffusion-source remarkup-code PhabricatorMonospaced',
|
2011-06-10 08:53:53 +02:00
|
|
|
),
|
|
|
|
implode("\n", $rows));
|
|
|
|
|
|
|
|
$corpus = phutil_render_tag(
|
|
|
|
'div',
|
|
|
|
array(
|
|
|
|
'style' => 'padding: 0pt 2em;',
|
|
|
|
),
|
|
|
|
$corpus_table);
|
|
|
|
|
|
|
|
return $corpus;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildDisplayRows($text_list) {
|
|
|
|
$rows = array();
|
|
|
|
$n = 1;
|
|
|
|
|
|
|
|
foreach ($text_list as $k => $line) {
|
|
|
|
// Pardon the ugly for the time being.
|
|
|
|
// And eventually this will highlight a line that you click
|
|
|
|
// like diffusion does. Or maybe allow for line comments
|
|
|
|
// like differential. Either way it will be better than it is now.
|
2012-02-08 03:55:33 +01:00
|
|
|
$anchor = 'L'.$n;
|
|
|
|
$link = phutil_render_tag(
|
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'name' => $anchor,
|
|
|
|
'href' => '#'.$anchor,
|
|
|
|
),
|
|
|
|
$n);
|
|
|
|
$rows[] = '<tr id="'.$anchor.'"><th>'.$link.'</th>'.
|
Kind-of-terrible (?) oncopy handler
Summary: Works in Safari, Firefox, Chrome.
Test Plan: Copied some text, threw up a little in my mouth.
Reviewers: aran, tuomaspelkonen, tomo, rstout, btrahan
Reviewed By: aran
CC: aran, epriestley, ddfisher
Maniphest Tasks: T145, T995
Differential Revision: https://secure.phabricator.com/D244
2012-03-16 03:04:59 +01:00
|
|
|
'<td style="white-space: pre-wrap;">'.
|
|
|
|
// NOTE: See the 'phabricator-oncopy' behavior.
|
|
|
|
"\xE2\x80\x8B".
|
|
|
|
$line.'</td></tr>';
|
2011-06-10 08:53:53 +02:00
|
|
|
++$n;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $rows;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|