Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/files/controller/transform/PhabricatorFileTransformController.php b/src/applications/files/controller/transform/PhabricatorFileTransformController.php
index c766bbbaca..7f3a42253d 100644
--- a/src/applications/files/controller/transform/PhabricatorFileTransformController.php
+++ b/src/applications/files/controller/transform/PhabricatorFileTransformController.php
@@ -1,131 +1,178 @@
<?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 PhabricatorFileTransformController extends PhabricatorFileController {
private $transform;
private $phid;
public function willProcessRequest(array $data) {
$this->transform = $data['transform'];
$this->phid = $data['phid'];
}
public function processRequest() {
$xform = id(new PhabricatorTransformedFile())
->loadOneWhere(
'originalPHID = %s AND transform = %s',
$this->phid,
$this->transform);
if ($xform) {
return $this->buildTransformedFileResponse($xform);
}
$file = id(new PhabricatorFile())->loadOneWhere('phid = %s', $this->phid);
if (!$file) {
return new Aphront404Response();
}
- if (!$file->isViewableInBrowser()) {
- return new Aphront400Response();
- }
+ $type = $file->getMimeType();
- if (!$file->isTransformableImage()) {
- return new Aphront400Response();
+ if (!$file->isViewableInBrowser() || !$file->isTransformableImage()) {
+ return $this->buildDefaultTransformation($file);
}
switch ($this->transform) {
case 'thumb-160x120':
$xformed_file = $this->executeThumbTransform($file, 160, 120);
break;
case 'thumb-60x45':
$xformed_file = $this->executeThumbTransform($file, 60, 45);
break;
case 'profile-50x50':
$xformed_file = $this->executeProfile50x50Transform($file);
break;
default:
return new Aphront400Response();
}
if (!$xformed_file) {
return new Aphront400Response();
}
$xform = new PhabricatorTransformedFile();
$xform->setOriginalPHID($this->phid);
$xform->setTransform($this->transform);
$xform->setTransformedPHID($xformed_file->getPHID());
$xform->save();
return $this->buildTransformedFileResponse($xform);
}
+ private function buildDefaultTransformation(PhabricatorFile $file) {
+ static $regexps = array(
+ '@application/zip@' => 'zip',
+ '@image/@' => 'image',
+ '@application/pdf@' => 'pdf',
+ '@.*@' => 'default',
+ );
+
+ $type = $file->getMimeType();
+ $prefix = 'default';
+ foreach ($regexps as $regexp => $implied_prefix) {
+ if (preg_match($regexp, $type)) {
+ $prefix = $implied_prefix;
+ break;
+ }
+ }
+
+ switch ($this->transform) {
+ case 'thumb-160x120':
+ $suffix = '160x120';
+ break;
+ case 'thumb-60x45':
+ $suffix = '60x45';
+ break;
+ default:
+ throw new Exception("Unsupported transformation type!");
+ }
+
+ $path = "/rsrc/image/icon/fatcow/thumbnails/{$prefix}{$suffix}.png";
+ return id(new AphrontRedirectResponse())
+ ->setURI($path);
+ }
+
private function buildTransformedFileResponse(
PhabricatorTransformedFile $xform) {
// TODO: We could just delegate to the file view controller instead,
// which would save the client a roundtrip, but is slightly more complex.
return id(new AphrontRedirectResponse())->setURI(
PhabricatorFileURI::getViewURIForPHID($xform->getTransformedPHID()));
}
private function executeProfile50x50Transform(PhabricatorFile $file) {
$data = $file->loadFileData();
$jpeg = $this->crudelyScaleTo($data, 50, 50);
return PhabricatorFile::newFromFileData($jpeg, array(
'name' => 'profile-'.$file->getName(),
));
}
private function executeThumbTransform(PhabricatorFile $file, $x, $y) {
$data = $file->loadFileData();
$jpeg = $this->crudelyScaleTo($data, $x, $y);
return PhabricatorFile::newFromFileData($jpeg, array(
'name' => 'thumb-'.$file->getName(),
));
}
/**
* Very crudely scale an image up or down to an exact size.
*/
private function crudelyScaleTo($data, $dx, $dy) {
$src = imagecreatefromstring($data);
$x = imagesx($src);
$y = imagesy($src);
$scale = min($x / $dx, $y / $dy);
$dst = imagecreatetruecolor($dx, $dy);
imagecopyresampled(
$dst,
$src,
0, 0,
0, 0,
$dx, $dy,
$scale * $dx, $scale * $dy);
- ob_start();
- imagejpeg($dst);
- return ob_get_clean();
+ $img = null;
+
+ if (function_exists('imagejpeg')) {
+ ob_start();
+ imagejpeg($dst);
+ $img = ob_get_clean();
+ } else if (function_exists('imagepng')) {
+ ob_start();
+ imagepng($dst);
+ $img = ob_get_clean();
+ } else if (function_exists('imagegif')) {
+ ob_start();
+ imagegif($dst);
+ $img = ob_get_clean();
+ } else {
+ throw new Exception("No image generation functions exist!");
+ }
+
+ return $img;
}
}
diff --git a/src/applications/files/storage/file/PhabricatorFile.php b/src/applications/files/storage/file/PhabricatorFile.php
index b2a53948cd..0c70be9320 100644
--- a/src/applications/files/storage/file/PhabricatorFile.php
+++ b/src/applications/files/storage/file/PhabricatorFile.php
@@ -1,232 +1,260 @@
<?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 PhabricatorFile extends PhabricatorFileDAO {
const STORAGE_ENGINE_BLOB = 'blob';
const STORAGE_FORMAT_RAW = 'raw';
// TODO: We need to reconcile this with MySQL packet size.
const FILE_SIZE_BYTE_LIMIT = 12582912;
protected $phid;
protected $name;
protected $mimeType;
protected $byteSize;
protected $storageEngine;
protected $storageFormat;
protected $storageHandle;
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(
PhabricatorPHIDConstants::PHID_TYPE_FILE);
}
public static function newFromPHPUpload($spec, array $params = array()) {
if (!$spec) {
throw new Exception("No file was uploaded!");
}
$err = idx($spec, 'error');
if ($err) {
throw new Exception("File upload failed with error '{$err}'.");
}
$tmp_name = idx($spec, 'tmp_name');
$is_valid = @is_uploaded_file($tmp_name);
if (!$is_valid) {
throw new Exception("File is not an uploaded file.");
}
$file_data = Filesystem::readFile($tmp_name);
$file_size = idx($spec, 'size');
if (strlen($file_data) != $file_size) {
throw new Exception("File size disagrees with uploaded size.");
}
$file_name = nonempty(
idx($params, 'name'),
idx($spec, 'name'));
$params = array(
'name' => $file_name,
) + $params;
return self::newFromFileData($file_data, $params);
}
public static function newFromFileData($data, array $params = array()) {
$file_size = strlen($data);
if ($file_size > self::FILE_SIZE_BYTE_LIMIT) {
throw new Exception("File is too large to store.");
}
$file_name = idx($params, 'name');
$file_name = self::normalizeFileName($file_name);
$file = new PhabricatorFile();
$file->setName($file_name);
$file->setByteSize(strlen($data));
$blob = new PhabricatorFileStorageBlob();
$blob->setData($data);
$blob->save();
// TODO: This stuff is almost certainly YAGNI, but we could imagine having
// an alternate disk store and gzipping or encrypting things or something
// crazy like that and this isn't toooo much extra code.
$file->setStorageEngine(self::STORAGE_ENGINE_BLOB);
$file->setStorageFormat(self::STORAGE_FORMAT_RAW);
$file->setStorageHandle($blob->getID());
if (isset($params['mime-type'])) {
$file->setMimeType($params['mime-type']);
} else {
try {
$tmp = new TempFile();
Filesystem::writeFile($tmp, $data);
list($stdout) = execx('file -b --mime %s', $tmp);
$file->setMimeType($stdout);
} catch (Exception $ex) {
// Be robust here since we don't really care that much about mime types.
}
}
$file->save();
return $file;
}
public static function newFromFileDownload($uri, $name) {
$uri = new PhutilURI($uri);
$protocol = $uri->getProtocol();
switch ($protocol) {
case 'http':
case 'https':
break;
default:
// Make sure we are not accessing any file:// URIs or similar.
return null;
}
$timeout = stream_context_create(
array(
'http' => array(
'timeout' => 5,
),
));
$file_data = @file_get_contents($uri, false, $timeout);
if ($file_data === false) {
return null;
}
return self::newFromFileData($file_data, array('name' => $name));
}
public static function normalizeFileName($file_name) {
return preg_replace('/[^a-zA-Z0-9.~_-]/', '_', $file_name);
}
public function delete() {
$this->openTransaction();
switch ($this->getStorageEngine()) {
case self::STORAGE_ENGINE_BLOB:
$handle = $this->getStorageHandle();
$blob = id(new PhabricatorFileStorageBlob())->load($handle);
$blob->delete();
break;
default:
throw new Exception("Unknown storage engine!");
}
$ret = parent::delete();
$this->saveTransaction();
return $ret;
}
public function loadFileData() {
$handle = $this->getStorageHandle();
$data = null;
switch ($this->getStorageEngine()) {
case self::STORAGE_ENGINE_BLOB:
$blob = id(new PhabricatorFileStorageBlob())->load($handle);
if (!$blob) {
throw new Exception("Failed to load file blob data.");
}
$data = $blob->getData();
break;
default:
throw new Exception("Unknown storage engine.");
}
switch ($this->getStorageFormat()) {
case self::STORAGE_FORMAT_RAW:
$data = $data;
break;
default:
throw new Exception("Unknown storage format.");
}
return $data;
}
public function getViewURI() {
return PhabricatorFileURI::getViewURIForPHID($this->getPHID());
}
public function getThumb60x45URI() {
return '/file/xform/thumb-60x45/'.$this->getPHID().'/';
}
public function getThumb160x120URI() {
return '/file/xform/thumb-160x120/'.$this->getPHID().'/';
}
public function isViewableInBrowser() {
return ($this->getViewableMimeType() !== null);
}
public function isTransformableImage() {
- return preg_match('@^image/(gif|png|jpe?g)@', $this->getViewableMimeType());
+
+ // NOTE: The way the 'gd' extension works in PHP is that you can install it
+ // with support for only some file types, so it might be able to handle
+ // PNG but not JPEG. Try to generate thumbnails for whatever we can. Setup
+ // warns you if you don't have complete support.
+
+ $matches = null;
+ $ok = preg_match(
+ '@^image/(gif|png|jpe?g)@',
+ $this->getViewableMimeType(),
+ $matches);
+ if (!$ok) {
+ return false;
+ }
+
+ switch ($matches[1]) {
+ case 'jpg';
+ case 'jpeg':
+ return function_exists('imagejpeg');
+ break;
+ case 'png':
+ return function_exists('imagepng');
+ break;
+ case 'gif':
+ return function_exists('imagegif');
+ break;
+ default:
+ throw new Exception('Unknown type matched as image MIME type.');
+ }
}
public function getViewableMimeType() {
$mime_map = PhabricatorEnv::getEnvConfig('files.viewable-mime-types');
$mime_type = $this->getMimeType();
$mime_parts = explode(';', $mime_type);
$mime_type = trim(reset($mime_parts));
return idx($mime_map, $mime_type);
}
}
diff --git a/src/infrastructure/setup/PhabricatorSetup.php b/src/infrastructure/setup/PhabricatorSetup.php
index 023de19800..ff4e559b79 100644
--- a/src/infrastructure/setup/PhabricatorSetup.php
+++ b/src/infrastructure/setup/PhabricatorSetup.php
@@ -1,447 +1,480 @@
<?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 PhabricatorSetup {
const EXPECTED_SCHEMA_VERSION = 36;
public static function runSetup() {
header("Content-Type: text/plain");
self::write("PHABRICATOR SETUP\n\n");
// Force browser to stop buffering.
self::write(str_repeat(' ', 2048));
usleep(250000);
self::write("This setup mode will guide you through setting up your ".
"Phabricator configuration.\n");
self::writeHeader("REQUIRED PHP EXTENSIONS");
$extensions = array(
'mysql',
'hash',
'json',
'openssl',
// There is a chance we might not need this, but some configurations (like
// Amazon SES) will require it. Just mark it 'required' since it's widely
// available and relatively core.
'curl',
);
foreach ($extensions as $extension) {
$ok = self::requireExtension($extension);
if (!$ok) {
self::writeFailure();
self::write("Setup failure! Install PHP extension '{$extension}'.");
return;
}
}
$root = dirname(phutil_get_library_root('phabricator'));
// On RHEL6, doing a distro install of pcntl makes it available from the
// CLI binary but not from the Apache module. This isn't entirely
// unreasonable and we don't need it from Apache, so do an explicit test
// for CLI availability.
list($err, $stdout, $stderr) = exec_manual(
'%s/scripts/setup/pcntl_available.php',
$root);
if ($err) {
self::writeFailure();
self::write("Unable to execute scripts/setup/pcntl_available.php.");
return;
} else {
if (trim($stdout) == 'YES') {
self::write(" okay pcntl is available from the command line.\n");
self::write("[OKAY] All extensions OKAY\n\n");
} else {
self::write(" warn pcntl is not available!\n");
self::write("[WARN] *** WARNING *** pcntl extension not available. ".
"You will not be able to run daemons.\n");
}
}
self::writeHeader("GIT SUBMODULES");
if (!Filesystem::pathExists($root.'/.git')) {
self::write(" skip Not a git clone.\n\n");
} else {
list($info) = execx(
'(cd %s && git submodule status)',
$root);
foreach (explode("\n", rtrim($info)) as $line) {
$matches = null;
if (!preg_match('/^(.)([0-9a-f]{40}) (\S+)(?: |$)/', $line, $matches)) {
self::writeFailure();
self::write(
"Setup failure! 'git submodule' produced unexpected output:\n".
$line);
return;
}
$status = $matches[1];
$module = $matches[3];
switch ($status) {
case '-':
case '+':
case 'U':
self::writeFailure();
self::write(
"Setup failure! Git submodule '{$module}' is not up to date. ".
"Run:\n\n".
" cd {$root} && git submodule update --init\n\n".
"...to update submodules.");
return;
case ' ':
self::write(" okay Git submodule '{$module}' up to date.\n");
break;
default:
self::writeFailure();
self::write(
"Setup failure! 'git submodule' reported unknown status ".
"'{$status}' for submodule '{$module}'. This is a bug; report ".
"it to the Phabricator maintainers.");
return;
}
}
}
self::write("[OKAY] All submodules OKAY.");
self::writeHeader("BASIC CONFIGURATION");
$env = PhabricatorEnv::getEnvConfig('phabricator.env');
if ($env == 'production' || $env == 'default' || $env == 'development') {
self::writeFailure();
self::write(
"Setup failure! Your PHABRICATOR_ENV is set to '{$env}', which is ".
"a Phabricator environmental default. You should create a custom ".
"environmental configuration instead of editing the defaults ".
"directly. See this document for instructions:\n");
self::writeDoc('article/Configuration_Guide.html');
return;
} else {
$host = PhabricatorEnv::getEnvConfig('phabricator.base-uri');
$protocol = id(new PhutilURI($host))->getProtocol();
$allowed_protocols = array(
'http' => true,
'https' => true,
);
if (empty($allowed_protocols[$protocol])) {
self::writeFailure();
self::write(
"You must specify the protocol over which your host works (e.g.: ".
"\"http:// or https://\")\nin your custom config file.\nRefer to ".
"'default.conf.php' for documentation on configuration options.\n");
return;
}
if (preg_match('/.*\/$/', $host)) {
self::write(" okay phabricator.base-uri\n");
} else {
self::writeFailure();
self::write(
"You must add a trailing slash at the end of the host\n(e.g.: ".
"\"http://phabricator.example.com/ instead of ".
"http://phabricator.example.com\")\nin your custom config file.".
"\nRefer to 'default.conf.php' for documentation on configuration ".
"options.\n");
return;
}
}
self::write("[OKAY] Basic configuration OKAY\n");
+
+ $issue_gd_warning = false;
+ self::writeHeader('GD LIBRARY');
+ if (extension_loaded('gd')) {
+ self::write(" okay Extension 'gd' is loaded.\n");
+ $image_type_map = array(
+ 'imagepng' => 'PNG',
+ 'imagegif' => 'GIF',
+ 'imagejpeg' => 'JPEG',
+ );
+ foreach ($image_type_map as $function => $image_type) {
+ if (function_exists($function)) {
+ self::write(" okay Support for '{$image_type}' is available.\n");
+ } else {
+ self::write(" warn Support for '{$image_type}' is not available!\n");
+ $issue_gd_warning = true;
+ }
+ }
+ } else {
+ self::write(" warn Extension 'gd' is not loaded.\n");
+ $issue_gd_warning = true;
+ }
+
+ if ($issue_gd_warning) {
+ self::write(
+ "[WARN] The 'gd' library is missing or lacks full support. ".
+ "Phabricator will not be able to generate image thumbnails without ".
+ "gd.\n");
+ } else {
+ self::write("[OKAY] 'gd' loaded and has full image type support.\n");
+ }
+
+
self::writeHeader('FACEBOOK INTEGRATION');
$fb_auth = PhabricatorEnv::getEnvConfig('facebook.auth-enabled');
if (!$fb_auth) {
self::write(" skip 'facebook.auth-enabled' not enabled.\n");
} else {
self::write(" okay 'facebook.auth-enabled' is enabled.\n");
$app_id = PhabricatorEnv::getEnvConfig('facebook.application-id');
$app_secret = PhabricatorEnv::getEnvConfig('facebook.application-secret');
if (!$app_id) {
self::writeFailure();
self::write(
"Setup failure! 'facebook.auth-enabled' is true but there is no ".
"setting for 'facebook.application-id'.\n");
return;
} else {
self::write(" okay 'facebook.application-id' is set.\n");
}
if (!is_string($app_id)) {
self::writeFailure();
self::write(
"Setup failure! 'facebook.application-id' should be a string.");
return;
} else {
self::write(" okay 'facebook.application-id' is string.\n");
}
if (!$app_secret) {
self::writeFailure();
self::write(
"Setup failure! 'facebook.auth-enabled' is true but there is no ".
"setting for 'facebook.application-secret'.");
return;
} else {
self::write(" okay 'facebook.application-secret is set.\n");
}
self::write("[OKAY] Facebook integration OKAY\n");
}
self::writeHeader("MySQL DATABASE CONFIGURATION");
$conn_user = PhabricatorEnv::getEnvConfig('mysql.user');
$conn_pass = PhabricatorEnv::getEnvConfig('mysql.pass');
$conn_host = PhabricatorEnv::getEnvConfig('mysql.host');
$timeout = ini_get('mysql.connect_timeout');
if ($timeout > 5) {
self::writeNote(
"Your MySQL connect timeout is very high ({$timeout} seconds). ".
"Consider reducing it by setting 'mysql.connect_timeout' in your ".
"php.ini.");
}
self::write(" okay Trying to connect to MySQL database ".
"{$conn_user}@{$conn_host}...\n");
ini_set('mysql.connect_timeout', 2);
$conn_raw = new AphrontMySQLDatabaseConnection(
array(
'user' => $conn_user,
'pass' => $conn_pass,
'host' => $conn_host,
'database' => null,
));
try {
queryfx($conn_raw, 'SELECT 1');
self::write(" okay Connection successful!\n");
} catch (AphrontQueryConnectionException $ex) {
self::writeFailure();
self::write(
"Setup failure! Unable to connect to MySQL database ".
"'{$conn_host}' with user '{$conn_user}'. Edit Phabricator ".
"configuration keys 'mysql.user', 'mysql.host' and 'mysql.pass' to ".
"enable Phabricator to connect.");
return;
}
$databases = queryfx_all($conn_raw, 'SHOW DATABASES');
$databases = ipull($databases, 'Database');
$databases = array_fill_keys($databases, true);
if (empty($databases['phabricator_meta_data'])) {
self::writeFailure();
self::write(
"Setup failure! You haven't loaded the 'initialize.sql' file into ".
"MySQL. This file initializes necessary databases. See this guide for ".
"instructions:\n");
self::writeDoc('article/Configuration_Guide.html');
return;
} else {
self::write(" okay Databases have been initialized.\n");
}
$schema_version = queryfx_one(
$conn_raw,
'SELECT version FROM phabricator_meta_data.schema_version');
$schema_version = idx($schema_version, 'version', 'null');
$expect = PhabricatorSQLPatchList::getExpectedSchemaVersion();
if ($schema_version != $expect) {
self::writeFailure();
self::write(
"Setup failure! You haven't upgraded your database schema to the ".
"latest version. Expected version is '{$expect}', but your local ".
"version is '{$schema_version}'. See this guide for instructions:\n");
self::writeDoc('article/Upgrading_Schema.html');
return;
} else {
self::write(" okay Database schema are up to date (v{$expect}).\n");
}
self::write("[OKAY] Database configuration OKAY\n");
self::writeHeader("OUTBOUND EMAIL CONFIGURATION");
$have_adapter = false;
$is_ses = false;
$adapter = PhabricatorEnv::getEnvConfig('metamta.mail-adapter');
switch ($adapter) {
case 'PhabricatorMailImplementationPHPMailerLiteAdapter':
$have_adapter = true;
if (!Filesystem::pathExists('/usr/bin/sendmail')) {
self::writeFailure();
self::write(
"Setup failure! You don't have a 'sendmail' binary on this system ".
"but outbound email is configured to use sendmail. Install an MTA ".
"(like sendmail, qmail or postfix) or use a different outbound ".
"mail configuration. See this guide for configuring outbound ".
"email:\n");
self::writeDoc('article/Configuring_Outbound_Email.html');
return;
} else {
self::write(" okay Sendmail is configured.\n");
}
break;
case 'PhabricatorMailImplementationAmazonSESAdapter':
$is_ses = true;
$have_adapter = true;
if (PhabricatorEnv::getEnvConfig('metamta.can-send-as-user')) {
self::writeFailure();
self::write(
"Setup failure! 'metamta.can-send-as-user' must be false when ".
"configured with Amazon SES.");
return;
} else {
self::write(" okay Sender config looks okay.\n");
}
if (!PhabricatorEnv::getEnvConfig('amazon-ses.access-key')) {
self::writeFailure();
self::write(
"Setup failure! 'amazon-ses.access-key' is not set, but ".
"outbound mail is configured to deliver via Amazon SES.");
return;
} else {
self::write(" okay Amazon SES access key is set.\n");
}
if (!PhabricatorEnv::getEnvConfig('amazon-ses.secret-key')) {
self::writeFailure();
self::write(
"Setup failure! 'amazon-ses.secret-key' is not set, but ".
"outbound mail is configured to deliver via Amazon SES.");
return;
} else {
self::write(" okay Amazon SES secret key is set.\n");
}
if (PhabricatorEnv::getEnvConfig('metamta.send-immediately')) {
self::writeNote(
"Your configuration uses Amazon SES to deliver email but tries ".
"to send it immediately. This will work, but it's slow. ".
"Consider configuring the MetaMTA daemon.");
}
break;
case 'PhabricatorMailImplementationTestAdapter':
self::write(" skip You have disabled outbound email.\n");
break;
default:
self::write(" skip Configured with a custom adapter.\n");
break;
}
if ($have_adapter) {
$default = PhabricatorEnv::getEnvConfig('metamta.default-address');
if (!$default || $default == 'noreply@example.com') {
self::writeFailure();
self::write(
"Setup failure! You have not set 'metamta.default-address'.");
return;
} else {
self::write(" okay metamta.default-address is set.\n");
}
if ($is_ses) {
self::writeNote(
"Make sure you've verified your 'from' address ('{$default}') with ".
"Amazon SES. Until you verify it, you will be unable to send mail ".
"using Amazon SES.");
}
$domain = PhabricatorEnv::getEnvConfig('metamta.domain');
if (!$domain || $domain == 'example.com') {
self::writeFailure();
self::write(
"Setup failure! You have not set 'metamta.domain'.");
return;
} else {
self::write(" okay metamta.domain is set.\n");
}
self::write("[OKAY] Mail configuration OKAY\n");
}
self::writeHeader('SUCCESS!');
self::write(
"Congratulations! Your setup seems mostly correct, or at least fairly ".
"reasonable.\n\n".
"*** NEXT STEP ***\n".
"Edit your configuration file (conf/{$env}.conf.php) and remove the ".
"'phabricator.setup' line to finish installation.");
}
public static function requireExtension($extension) {
if (extension_loaded($extension)) {
self::write(" okay Extension '{$extension}' installed.\n");
return true;
} else {
self::write("[FAIL] Extension '{$extension}' is NOT INSTALLED!\n");
return false;
}
}
private static function writeFailure() {
self::write("\n\n<<< *** FAILURE! *** >>>\n");
}
private static function write($str) {
echo $str;
ob_flush();
flush();
// This, uh, makes it look cool. -_-
usleep(40000);
}
private static function writeNote($note) {
self::write(
'Note: '.wordwrap($note, 75, "\n ", true)."\n\n");
}
public static function writeHeader($header) {
$template = '>>>'.str_repeat('-', 77);
$template = substr_replace(
$template,
' '.$header.' ',
3,
strlen($header) + 4);
self::write("\n\n{$template}\n\n");
}
public static function writeDoc($doc) {
self::write(
"\n".
' http://phabricator.com/docs/phabricator/'.$doc.
"\n\n");
}
}
diff --git a/webroot/rsrc/image/icon/fatcow/thumbnails/default160x120.png b/webroot/rsrc/image/icon/fatcow/thumbnails/default160x120.png
new file mode 100644
index 0000000000..16d6fd4f90
Binary files /dev/null and b/webroot/rsrc/image/icon/fatcow/thumbnails/default160x120.png differ
diff --git a/webroot/rsrc/image/icon/fatcow/thumbnails/default60x45.png b/webroot/rsrc/image/icon/fatcow/thumbnails/default60x45.png
new file mode 100644
index 0000000000..145ea1eb63
Binary files /dev/null and b/webroot/rsrc/image/icon/fatcow/thumbnails/default60x45.png differ
diff --git a/webroot/rsrc/image/icon/fatcow/thumbnails/image160x120.png b/webroot/rsrc/image/icon/fatcow/thumbnails/image160x120.png
new file mode 100644
index 0000000000..90cc11c02d
Binary files /dev/null and b/webroot/rsrc/image/icon/fatcow/thumbnails/image160x120.png differ
diff --git a/webroot/rsrc/image/icon/fatcow/thumbnails/image60x45.png b/webroot/rsrc/image/icon/fatcow/thumbnails/image60x45.png
new file mode 100644
index 0000000000..9077e69586
Binary files /dev/null and b/webroot/rsrc/image/icon/fatcow/thumbnails/image60x45.png differ
diff --git a/webroot/rsrc/image/icon/fatcow/thumbnails/pdf160x120.png b/webroot/rsrc/image/icon/fatcow/thumbnails/pdf160x120.png
new file mode 100644
index 0000000000..20f08f955b
Binary files /dev/null and b/webroot/rsrc/image/icon/fatcow/thumbnails/pdf160x120.png differ
diff --git a/webroot/rsrc/image/icon/fatcow/thumbnails/pdf60x45.png b/webroot/rsrc/image/icon/fatcow/thumbnails/pdf60x45.png
new file mode 100644
index 0000000000..8a16eaf488
Binary files /dev/null and b/webroot/rsrc/image/icon/fatcow/thumbnails/pdf60x45.png differ
diff --git a/webroot/rsrc/image/icon/fatcow/thumbnails/zip160x120.png b/webroot/rsrc/image/icon/fatcow/thumbnails/zip160x120.png
new file mode 100644
index 0000000000..fbe19e59f6
Binary files /dev/null and b/webroot/rsrc/image/icon/fatcow/thumbnails/zip160x120.png differ
diff --git a/webroot/rsrc/image/icon/fatcow/thumbnails/zip60x45.png b/webroot/rsrc/image/icon/fatcow/thumbnails/zip60x45.png
new file mode 100644
index 0000000000..c66416c318
Binary files /dev/null and b/webroot/rsrc/image/icon/fatcow/thumbnails/zip60x45.png differ

File Metadata

Mime Type
text/x-diff
Expires
Wed, Dec 3, 11:27 AM (11 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
433303
Default Alt Text
(31 KB)

Event Timeline