- php5-curl Fetching files by HTTP.
- php5-gd Image manipulation (scaling).
- php5-gmp For Salmon signatures (part of OStatus).
+- php5-intl Internationalization support (transliteration et al).
- php5-json For WebFinger lookups and more.
- php5-mysqlnd The native driver for PHP5 MariaDB connections. If you
use MySQL, 'mysql' or 'mysqli' may work.
- Many improvements to ease adoption of the Qvitter front-end <https://github.com/hannesmannerheim/qvitter>
- Protocol adaptions for improved performance and stability
- Backing up a user's account now appears to work as it should
+- Emojis 😸
Upgrades from _StatusNet_ 1.1.1 will also experience these improvements:
* @link http://status.net/
*/
-if (!defined('STATUSNET')) {
- exit(1);
-}
+if (!defined('GNUSOCIAL')) { exit(1); }
/**
* Allows the authenticating users to follow (subscribe) the user specified in
$this->clientError(_('Could not follow user: profile not found.'), 403);
}
- if ($this->user->isSubscribed($this->other)) {
+ if ($this->scoped->isSubscribed($this->other)) {
$errmsg = sprintf(
// TRANS: Client error displayed when trying to follow a user that's already being followed.
// TRANS: %s is the nickname of the user that is already being followed.
}
try {
- Subscription::start($this->user->getProfile(), $this->other);
+ Subscription::start($this->scoped, $this->other);
} catch (Exception $e) {
$this->clientError($e->getMessage(), 403);
}
* @link http://status.net/
*/
-if (!defined('STATUSNET')) {
- exit(1);
-}
+if (!defined('GNUSOCIAL')) { exit(1); }
/**
* Allows the authenticating users to unfollow (unsubscribe) the user specified in
*/
class ApiFriendshipsDestroyAction extends ApiAuthAction
{
- var $other = null;
+ protected $needPost = true;
+
+ protected $other = null;
/**
* Take arguments for running
* @return boolean success flag
*
*/
- function prepare($args)
+ protected function prepare(array $args=array())
{
parent::prepare($args);
- $this->user = $this->auth_user;
- $this->other = $this->getTargetProfile($this->arg('id'));
+ $this->other = $this->getTargetProfile($this->arg('id'));
return true;
}
*
* Check the format and show the user info
*
- * @param array $args $_REQUEST data (unused)
- *
* @return void
*/
- function handle($args)
+ protected function handle()
{
- parent::handle($args);
-
- if ($_SERVER['REQUEST_METHOD'] != 'POST') {
- $this->clientError(
- // TRANS: Client error. POST is a HTTP command. It should not be translated.
- _('This method requires a POST.'),
- 400,
- $this->format
- );
- return;
- }
+ parent::handle();
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(
// TRANS: Client error displayed when coming across a non-supported API method.
_('API method not found.'),
- 404,
- $this->format
+ 404
);
- return;
}
- if (empty($this->other)) {
+ if (!$this->other instanceof Profile) {
$this->clientError(
// TRANS: Client error displayed when trying to unfollow a user that cannot be found.
_('Could not unfollow user: User not found.'),
- 403,
- $this->format
+ 403
);
- return;
}
// Don't allow unsubscribing from yourself!
- if ($this->user->id == $this->other->id) {
+ if ($this->scoped->id == $this->other->id) {
$this->clientError(
// TRANS: Client error displayed when trying to unfollow self.
_("You cannot unfollow yourself."),
- 403,
- $this->format
+ 403
);
- return;
}
// throws an exception on error
- Subscription::cancel($this->user->getProfile(), $this->other);
+ Subscription::cancel($this->scoped, $this->other);
$this->initDocument($this->format);
$this->showProfile($this->other, $this->format);
* @link http://status.net/
*/
-if (!defined('STATUSNET')) {
- exit(1);
-}
+if (!defined('GNUSOCIAL')) { exit(1); }
/**
* Tests for the existence of friendship between two users. Will return true if
*
* @return boolean success flag
*/
- function prepare($args)
+ protected function prepare(array $args=array())
{
parent::prepare($args);
*
* Check the format and show the user info
*
- * @param array $args $_REQUEST data (unused)
- *
* @return void
*/
- function handle($args)
+ protected function handle()
{
- parent::handle($args);
+ parent::handle();
if (empty($this->profile_a) || empty($this->profile_b)) {
$this->clientError(
// TRANS: Client error displayed when supplying invalid parameters to an API call checking if a friendship exists.
_('Two valid IDs or nick names must be supplied.'),
- 400,
- $this->format
+ 400
);
- return;
}
$result = Subscription::exists($this->profile_a, $this->profile_b);
* @link http://status.net/
*/
-if (!defined('STATUSNET')) {
- exit(1);
-}
+if (!defined('GNUSOCIAL')) { exit(1); }
/**
* Outputs detailed information about the relationship between two users
*
* @return boolean success flag
*/
- function prepare($args)
+ protected function prepare(array $args=array())
{
parent::prepare($args);
*
* Check the format and show the user info
*
- * @param array $args $_REQUEST data (unused)
- *
* @return void
*/
- function handle($args)
+ protected function handle()
{
- parent::handle($args);
+ parent::handle();
if (!in_array($this->format, array('xml', 'json'))) {
// TRANS: Client error displayed when coming across a non-supported API method.
* @link http://status.net/
*/
-if (!defined('STATUSNET')) {
- exit(1);
-}
+if (!defined('GNUSOCIAL')) { exit(1); }
/**
* Show most recent notices that are repeats in user's inbox
*
* @return boolean success flag
*/
- function prepare($args)
+ protected function prepare(array $args=array())
{
parent::prepare($args);
*
* show a timeline of the user's repeated notices
*
- * @param array $args $_REQUEST data (unused)
- *
* @return void
*/
- function handle($args)
+ protected function handle()
{
- parent::handle($args);
+ parent::handle();
$offset = ($this->page-1) * $this->cnt;
$limit = $this->cnt;
// TRANS: Title for Atom feed "repeated to me". %s is the user nickname.
- $title = sprintf(_("Repeated to %s"), $this->auth_user->nickname);
+ $title = sprintf(_("Repeated to %s"), $this->scoped->getNickname());
$subtitle = sprintf(
// @todo FIXME: $profile is not defined.
// TRANS: Subtitle for API action that shows most recent notices that are repeats in user's inbox.
// TRANS: %1$s is the sitename, %2$s is a user nickname, %3$s is a user profile name.
_('%1$s notices that were to repeated to %2$s / %3$s.'),
- $sitename, $this->user->nickname, $profile->getBestName()
+ $sitename, $this->scoped->getNickname(), $profile->getBestName()
);
$taguribase = TagURI::base();
- $id = "tag:$taguribase:RepeatedToMe:" . $this->auth_user->id;
+ $id = "tag:$taguribase:RepeatedToMe:" . $this->scoped->id;
$link = common_local_url(
'all',
- array('nickname' => $this->auth_user->nickname)
+ array('nickname' => $this->scoped->getNickname())
);
- $strm = $this->auth_user->repeatedToMe($offset, $limit, $this->since_id, $this->max_id);
+ $strm = $this->scoped->repeatedToMe($offset, $limit, $this->since_id, $this->max_id);
switch ($this->format) {
case 'xml':
case 'atom':
header('Content-Type: application/atom+xml; charset=utf-8');
- $atom = new AtomNoticeFeed($this->auth_user);
+ $atom = new AtomNoticeFeed($this->scoped->getUser());
$atom->setId($id);
$atom->setTitle($title);
break;
case 'as':
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
- $doc = new ActivityStreamJSONDocument($this->auth_user);
+ $doc = new ActivityStreamJSONDocument($this->scoped->getUser());
$doc->setTitle($title);
$doc->addLink($link, 'alternate', 'text/html');
$doc->addItemsFromNotices($strm);
// Get (safe!) HTML and text versions of the content
- $rendered = $this->purify($sourceContent);
+ $rendered = common_purify($sourceContent);
$content = common_strip_html($rendered);
$shortened = $this->auth_user->shortenLinks($content);
return $saved;
}
-
- function purify($content)
- {
- require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
-
- $config = array('safe' => 1,
- 'deny_attribute' => 'id,style,on*');
- return htmLawed($content, $config);
- }
}
*/
function savePreferences()
{
- $user = common_current_user();
+ $user = $this->scoped->getUser();
if (Event::handle('StartEmailSaveForm', array($this, $this->scoped))) {
$emailnotifysub = $this->boolean('emailnotifysub');
$emailmicroid = $this->boolean('emailmicroid');
$emailpost = $this->boolean('emailpost');
- assert(!is_null($user)); // should already be checked
-
$user->query('BEGIN');
$original = clone($user);
if ($result === false) {
common_log_db_error($user, 'UPDATE', __FILE__);
+ $user->query('ROLLBACK');
// TRANS: Server error thrown on database error updating e-mail preferences.
$this->serverError(_('Could not update user.'));
}
public $__table = 'attention'; // table name
public $notice_id; // int(4) primary_key not_null
public $profile_id; // int(4) primary_key not_null
- public $reason; // varchar(255)
+ public $reason; // varchar(191) not 255 because utf8mb4 takes more space
public $created; // datetime() not_null
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
'fields' => array(
'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice_id to give attention'),
'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'profile_id for feed receiver'),
- 'reason' => array('type' => 'varchar', 'length' => 255, 'description' => 'Optional reason why this was brought to the attention of profile_id'),
+ 'reason' => array('type' => 'varchar', 'length' => 191, 'description' => 'Optional reason why this was brought to the attention of profile_id'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
public $width; // int(4) primary_key not_null
public $height; // int(4) primary_key not_null
public $mediatype; // varchar(32) not_null
- public $filename; // varchar(255)
- public $url; // varchar(255) unique_key
+ public $filename; // varchar(191) not 255 because utf8mb4 takes more space
+ public $url; // varchar(191) unique_key not 255 because utf8mb4 takes more space
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
'width' => array('type' => 'int', 'not null' => true, 'description' => 'image width'),
'height' => array('type' => 'int', 'not null' => true, 'description' => 'image height'),
'mediatype' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'file type'),
- 'filename' => array('type' => 'varchar', 'length' => 255, 'description' => 'local filename, if local'),
- 'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'avatar location'),
+ 'filename' => array('type' => 'varchar', 'length' => 191, 'description' => 'local filename, if local'),
+ 'url' => array('type' => 'varchar', 'length' => 191, 'description' => 'avatar location'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
public $__table = 'config'; // table name
public $section; // varchar(32) primary_key not_null
public $setting; // varchar(32) primary_key not_null
- public $value; // varchar(255)
+ public $value; // varchar(191) not 255 because utf8mb4 takes more space
/* the code above is auto generated do not remove the tag below */
###END_AUTOCODE
'fields' => array(
'section' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'default' => '', 'description' => 'configuration section'),
'setting' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'default' => '', 'description' => 'configuration setting'),
- 'value' => array('type' => 'varchar', 'length' => 255, 'description' => 'configuration value'),
+ 'value' => array('type' => 'varchar', 'length' => 191, 'description' => 'configuration value'),
),
'primary key' => array('section', 'setting'),
);
public $__table = 'confirm_address'; // table name
public $code; // varchar(32) primary_key not_null
public $user_id; // int(4) not_null
- public $address; // varchar(255) not_null
- public $address_extra; // varchar(255) not_null
+ public $address; // varchar(191) not_null not 255 because utf8mb4 takes more space
+ public $address_extra; // varchar(191) not_null not 255 because utf8mb4 takes more space
public $address_type; // varchar(8) not_null
public $claimed; // datetime()
public $sent; // datetime()
'fields' => array(
'code' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'good random code'),
'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user who requested confirmation'),
- 'address' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'address (email, xmpp, SMS, etc.)'),
- 'address_extra' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'carrier ID, for SMS'),
+ 'address' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'address (email, xmpp, SMS, etc.)'),
+ 'address_extra' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'carrier ID, for SMS'),
'address_type' => array('type' => 'varchar', 'length' => 8, 'not null' => true, 'description' => 'address type ("email", "xmpp", "sms")'),
'claimed' => array('type' => 'datetime', 'description' => 'date this was claimed for queueing'),
'sent' => array('type' => 'datetime', 'description' => 'date this was sent for queueing'),
/* the code below is auto generated do not remove the above tag */
public $__table = 'consumer'; // table name
- public $consumer_key; // varchar(255) primary_key not_null
- public $consumer_secret; // varchar(255) not_null
+ public $consumer_key; // varchar(191) primary_key not_null not 255 because utf8mb4 takes more space
+ public $consumer_secret; // varchar(191) not_null not 255 because utf8mb4 takes more space
public $seed; // char(32) not_null
public $created; // datetime not_null
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
return array(
'description' => 'OAuth consumer record',
'fields' => array(
- 'consumer_key' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'unique identifier, root URL'),
- 'consumer_secret' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'secret value'),
+ 'consumer_key' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'unique identifier, root URL'),
+ 'consumer_secret' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'secret value'),
'seed' => array('type' => 'char', 'length' => 32, 'not null' => true, 'description' => 'seed for new tokens by this consumer'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
{
public $__table = 'conversation'; // table name
public $id; // int(4) primary_key not_null
- public $uri; // varchar(255) unique_key
+ public $uri; // varchar(191) unique_key not 255 because utf8mb4 takes more space
public $created; // datetime not_null
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
return array(
'fields' => array(
'id' => array('type' => 'int', 'not null' => true, 'description' => 'should be set from root notice id (since 2014-03-01 commit)'),
- 'uri' => array('type' => 'varchar', 'not null'=>true, 'length' => 255, 'description' => 'URI of the conversation'),
+ 'uri' => array('type' => 'varchar', 'not null'=>true, 'length' => 191, 'description' => 'URI of the conversation'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
public $__table = 'deleted_notice'; // table name
public $id; // int(4) primary_key not_null
public $profile_id; // int(4) not_null
- public $uri; // varchar(255) unique_key
+ public $uri; // varchar(191) unique_key not 255 because utf8mb4 takes more space
public $created; // datetime() not_null
public $deleted; // datetime() not_null
'fields' => array(
'id' => array('type' => 'int', 'not null' => true, 'description' => 'identity of notice'),
'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'author of the notice'),
- 'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier, usually a tag URI'),
+ 'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier, usually a tag URI'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date the notice record was created'),
'deleted' => array('type' => 'datetime', 'not null' => true, 'description' => 'date the notice record was created'),
),
{
public $__table = 'file'; // table name
public $id; // int(4) primary_key not_null
- public $url; // varchar(255) unique_key
+ public $urlhash; // varchar(64) unique_key
+ public $url; // text
+ public $filehash; // varchar(64) indexed
public $mimetype; // varchar(50)
public $size; // int(4)
- public $title; // varchar(255)
+ public $title; // varchar(191) not 255 because utf8mb4 takes more space
public $date; // int(4)
public $protected; // int(4)
- public $filename; // varchar(255)
+ public $filename; // varchar(191) not 255 because utf8mb4 takes more space
public $width; // int(4)
public $height; // int(4)
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+ const URLHASH_ALG = 'sha256';
+ const FILEHASH_ALG = 'sha256';
+
public static function schemaDef()
{
return array(
'fields' => array(
'id' => array('type' => 'serial', 'not null' => true),
- 'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'destination URL after following redirections'),
+ 'urlhash' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'sha256 of destination URL (url field)'),
+ 'url' => array('type' => 'text', 'description' => 'destination URL after following possible redirections'),
+ 'filehash' => array('type' => 'varchar', 'length' => 64, 'not null' => false, 'description' => 'sha256 of the file contents, only for locally stored files of course'),
'mimetype' => array('type' => 'varchar', 'length' => 50, 'description' => 'mime type of resource'),
'size' => array('type' => 'int', 'description' => 'size of resource when available'),
- 'title' => array('type' => 'varchar', 'length' => 255, 'description' => 'title of resource when available'),
+ 'title' => array('type' => 'varchar', 'length' => 191, 'description' => 'title of resource when available'),
'date' => array('type' => 'int', 'description' => 'date of resource according to http query'),
'protected' => array('type' => 'int', 'description' => 'true when URL is private (needs login)'),
- 'filename' => array('type' => 'varchar', 'length' => 255, 'description' => 'if a local file, name of the file'),
+ 'filename' => array('type' => 'varchar', 'length' => 191, 'description' => 'if a local file, name of the file'),
'width' => array('type' => 'int', 'description' => 'width in pixels, if it can be described as such and data is available'),
'height' => array('type' => 'int', 'description' => 'height in pixels, if it can be described as such and data is available'),
),
'primary key' => array('id'),
'unique keys' => array(
- 'file_url_key' => array('url'),
+ 'file_urlhash_key' => array('urlhash'),
+ ),
+ 'indexes' => array(
+ 'file_filehash_idx' => array('filehash'),
),
);
}
// I don't know why we have to keep doing this but I'm adding this last check to avoid
// uniqueness bugs.
- $file = File::getKV('url', $given_url);
+ $file = File::getKV('urlhash', self::hashurl($given_url));
if (!$file instanceof File) {
$file = new File;
+ $file->urlhash = self::hashurl($given_url);
$file->url = $given_url;
if (!empty($redir_data['protected'])) $file->protected = $redir_data['protected'];
if (!empty($redir_data['title'])) $file->title = $redir_data['title'];
throw new ServerException('No canonical URL from given URL to process');
}
- $file = File::getKV('url', $given_url);
- if (!$file instanceof File) {
+ $file = null;
+
+ try {
+ $file = File::getByUrl($given_url);
+ } catch (NoResultException $e) {
// First check if we have a lookup trace for this URL already
- $file_redir = File_redirection::getKV('url', $given_url);
- if ($file_redir instanceof File_redirection) {
+ try {
+ $file_redir = File_redirection::getByUrl($given_url);
$file = File::getKV('id', $file_redir->file_id);
if (!$file instanceof File) {
// File did not exist, let's clean up the File_redirection entry
$file_redir->delete();
}
+ } catch (NoResultException $e) {
+ // We just wanted to doublecheck whether a File_thumbnail we might've had
+ // actually referenced an existing File object.
}
+ }
- // If we still don't have a File object, let's create one now!
- if (!$file instanceof File) {
- // @fixme for new URLs this also looks up non-redirect data
- // such as target content type, size, etc, which we need
- // for File::saveNew(); so we call it even if not following
- // new redirects.
- $redir_data = File_redirection::where($given_url);
- if (is_array($redir_data)) {
- $redir_url = $redir_data['url'];
- } elseif (is_string($redir_data)) {
- $redir_url = $redir_data;
- $redir_data = array();
- } else {
- // TRANS: Server exception thrown when a URL cannot be processed.
- throw new ServerException(sprintf(_("Cannot process URL '%s'"), $given_url));
- }
+ // If we still don't have a File object, let's create one now!
+ if (!$file instanceof File) {
+ // @fixme for new URLs this also looks up non-redirect data
+ // such as target content type, size, etc, which we need
+ // for File::saveNew(); so we call it even if not following
+ // new redirects.
+ $redir_data = File_redirection::where($given_url);
+ if (is_array($redir_data)) {
+ $redir_url = $redir_data['url'];
+ } elseif (is_string($redir_data)) {
+ $redir_url = $redir_data;
+ $redir_data = array();
+ } else {
+ // TRANS: Server exception thrown when a URL cannot be processed.
+ throw new ServerException(sprintf(_("Cannot process URL '%s'"), $given_url));
+ }
- // TODO: max field length
- if ($redir_url === $given_url || strlen($redir_url) > 255 || !$followRedirects) {
- // Save the File object based on our lookup trace
- $file = File::saveNew($redir_data, $given_url);
- } else {
- // This seems kind of messed up... for now skipping this part
- // if we're already under a redirect, so we don't go into
- // horrible infinite loops if we've been given an unstable
- // redirect (where the final destination of the first request
- // doesn't match what we get when we ask for it again).
- //
- // Seen in the wild with clojure.org, which redirects through
- // wikispaces for auth and appends session data in the URL params.
- $file = self::processNew($redir_url, $notice_id, /*followRedirects*/false);
- File_redirection::saveNew($redir_data, $file->id, $given_url);
- }
+ if ($redir_url === $given_url || !$followRedirects) {
+ // Save the File object based on our lookup trace
+ $file = File::saveNew($redir_data, $given_url);
+ } else {
+ // This seems kind of messed up... for now skipping this part
+ // if we're already under a redirect, so we don't go into
+ // horrible infinite loops if we've been given an unstable
+ // redirect (where the final destination of the first request
+ // doesn't match what we get when we ask for it again).
+ //
+ // Seen in the wild with clojure.org, which redirects through
+ // wikispaces for auth and appends session data in the URL params.
+ $file = self::processNew($redir_url, $notice_id, /*followRedirects*/false);
+ File_redirection::saveNew($redir_data, $file->id, $given_url);
}
if (!$file instanceof File) {
static function filename(Profile $profile, $origname, $mimetype)
{
- try {
- $ext = common_supported_mime_to_ext($mimetype);
- } catch (Exception $e) {
- // We don't support this mimetype, but let's guess the extension
- $ext = substr(strrchr($mimetype, '/'), 1);
- }
+ $ext = self::guessMimeExtension($mimetype);
// Normalize and make the original filename more URL friendly.
$origname = basename($origname, ".$ext");
return $filename;
}
+ static function guessMimeExtension($mimetype)
+ {
+ try {
+ $ext = common_supported_mime_to_ext($mimetype);
+ } catch (Exception $e) {
+ // We don't support this mimetype, but let's guess the extension
+ $ext = substr(strrchr($mimetype, '/'), 1);
+ }
+ return strtolower($ext);
+ }
+
/**
* Validation for as-saved base filenames
*/
}
// throws exception on failure to generate thumbnail
- $outname = "thumb-{$width}x{$height}-" . $image->filename;
+ $outname = "thumb-{$width}x{$height}-{$image->filename}." . File::guessMimeExtension($image->mimetype);
$outpath = self::path($outname);
// The boundary box for our resizing
public function getPath()
{
- return self::path($this->filename);
+ $filepath = self::path($this->filename);
+ if (!file_exists($filepath)) {
+ throw new FileNotFoundException($filepath);
+ }
+ return $filepath;
}
public function getUrl()
if (!empty($this->filename)) {
// A locally stored file, so let's generate a URL for our instance.
$url = self::url($this->filename);
- if ($url != $this->url) {
+ if (self::hashurl($url) !== $this->urlhash) {
// For indexing purposes, in case we do a lookup on the 'url' field.
// also we're fixing possible changes from http to https, or paths
$this->updateUrl($url);
return $this->url;
}
+ static public function getByUrl($url)
+ {
+ $file = new File();
+ $file->urlhash = self::hashurl($url);
+ if (!$file->find(true)) {
+ throw new NoResultException($file);
+ }
+ return $file;
+ }
+
+ /**
+ * @param string $hashstr String of (preferrably lower case) hexadecimal characters, same as result of 'hash_file(...)'
+ */
+ static public function getByHash($hashstr, $alg=File::FILEHASH_ALG)
+ {
+ $file = new File();
+ $file->filehash = strtolower($hashstr);
+ if (!$file->find(true)) {
+ throw new NoResultException($file);
+ }
+ return $file;
+ }
+
public function updateUrl($url)
{
- $file = File::getKV('url', $url);
+ $file = File::getKV('urlhash', self::hashurl($url));
if ($file instanceof File) {
throw new ServerException('URL already exists in DB');
}
- $sql = 'UPDATE %1$s SET url=%2$s WHERE url=%3$s;';
+ $sql = 'UPDATE %1$s SET urlhash=%2$s, url=%3$s WHERE urlhash=%4$s;';
$result = $this->query(sprintf($sql, $this->__table,
+ $this->_quote((string)self::hashurl($url)),
$this->_quote((string)$url),
- $this->_quote((string)$this->url)));
+ $this->_quote((string)$this->urlhash)));
if ($result === false) {
common_log_db_error($this, 'UPDATE', __FILE__);
throw new ServerException("Could not UPDATE {$this->__table}.url");
function blowCache($last=false)
{
- self::blow('file:notice-ids:%s', $this->url);
+ self::blow('file:notice-ids:%s', $this->urlhash);
if ($last) {
- self::blow('file:notice-ids:%s;last', $this->url);
+ self::blow('file:notice-ids:%s;last', $this->urlhash);
}
self::blow('file:notice-count:%d', $this->id);
}
return $title ?: null;
}
+
+ static public function hashurl($url)
+ {
+ if (empty($url)) {
+ throw new Exception('No URL provided to hash algorithm.');
+ }
+ return hash(self::URLHASH_ALG, $url);
+ }
+
+ static public function beforeSchemaUpdate()
+ {
+ $table = strtolower(get_called_class());
+ $schema = Schema::get();
+ $schemadef = $schema->getTableDef($table);
+
+ // 2015-02-19 We have to upgrade our table definitions to have the urlhash field populated
+ if (isset($schemadef['fields']['urlhash']) && isset($schemadef['unique keys']['file_urlhash_key'])) {
+ // We already have the urlhash field, so no need to migrate it.
+ return;
+ }
+ echo "\nFound old $table table, upgrading it to contain 'urlhash' field...";
+ // We have to create a urlhash that is _not_ the primary key,
+ // transfer data and THEN run checkSchema
+ $schemadef['fields']['urlhash'] = array (
+ 'type' => 'varchar',
+ 'length' => 64,
+ 'not null' => true,
+ 'description' => 'sha256 of destination URL (url field)',
+ );
+ $schemadef['fields']['url'] = array (
+ 'type' => 'text',
+ 'description' => 'destination URL after following possible redirections',
+ );
+ unset($schemadef['unique keys']);
+ $schema->ensureTable($table, $schemadef);
+ echo "DONE.\n";
+
+ $classname = ucfirst($table);
+ $tablefix = new $classname;
+ // urlhash is hash('sha256', $url) in the File table
+ echo "Updating urlhash fields in $table table...";
+ // Maybe very MySQL specific :(
+ $tablefix->query(sprintf('UPDATE %1$s SET %2$s=%3$s;',
+ $schema->quoteIdentifier($table),
+ 'urlhash',
+ // The line below is "result of sha256 on column `url`"
+ 'SHA2(url, 256)'));
+ echo "DONE.\n";
+ echo "Resuming core schema upgrade...";
+ }
}
/* the code below is auto generated do not remove the above tag */
public $__table = 'file_redirection'; // table name
- public $url; // varchar(255) primary_key not_null
+ public $urlhash; // varchar(64) primary_key not_null
+ public $url; // text
public $file_id; // int(4)
public $redirections; // int(4)
public $httpcode; // int(4)
{
return array(
'fields' => array(
- 'url' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'short URL (or any other kind of redirect) for file (id)'),
+ 'urlhash' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'sha256 hash of the URL'),
+ 'url' => array('type' => 'text', 'description' => 'short URL (or any other kind of redirect) for file (id)'),
'file_id' => array('type' => 'int', 'description' => 'short URL for what URL/file'),
'redirections' => array('type' => 'int', 'description' => 'redirect count'),
'httpcode' => array('type' => 'int', 'description' => 'HTTP status code (20x, 30x, etc.)'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
- 'primary key' => array('url'),
+ 'primary key' => array('urlhash'),
'foreign keys' => array(
'file_redirection_file_id_fkey' => array('file' => array('file_id' => 'id')),
),
);
}
+ static public function getByUrl($url)
+ {
+ $file = new File_redirection();
+ $file->urlhash = File::hashurl($url);
+ if (!$file->find(true)) {
+ throw new NoResultException($file);
+ }
+ return $file;
+ }
+
static function _commonHttp($url, $redirs) {
$request = new HTTPClient($url);
$request->setConfig(array(
*/
public function where($in_url, $discover=true) {
// let's see if we know this...
- $a = File::getKV('url', $in_url);
-
- if (!empty($a)) {
+ try {
+ $a = File::getByUrl($in_url);
// this is a direct link to $a->url
return $a->url;
- } else {
- $b = File_redirection::getKV('url', $in_url);
- if (!empty($b)) {
+ } catch (NoResultException $e) {
+ try {
+ $b = File_redirection::getByUrl($in_url);
// this is a redirect to $b->file_id
$a = File::getKV('id', $b->file_id);
return $a->url;
+ } catch (NoResultException $e) {
+ // Oh well, let's keep going
}
}
$file_redir = File_redirection::getKV('url', $short_url);
if (!$file_redir instanceof File_redirection) {
$file_redir = new File_redirection;
+ $file_redir->urlhash = File::hashurl($short_url);
$file_redir->url = $short_url;
$file_redir->file_id = $file_id;
$file_redir->insert();
function saveNew($data, $file_id, $url) {
$file_redir = new File_redirection;
+ $file_redir->urlhash = File::hashurl($short_url);
$file_redir->url = $url;
$file_redir->file_id = $file_id;
$file_redir->redirections = intval($data['redirects']);
$file_redir->httpcode = intval($data['code']);
$file_redir->insert();
}
+
+ static public function beforeSchemaUpdate()
+ {
+ $table = strtolower(get_called_class());
+ $schema = Schema::get();
+ $schemadef = $schema->getTableDef($table);
+
+ // 2015-02-19 We have to upgrade our table definitions to have the urlhash field populated
+ if (isset($schemadef['fields']['urlhash']) && in_array('urlhash', $schemadef['primary key'])) {
+ // We already have the urlhash field, so no need to migrate it.
+ return;
+ }
+ echo "\nFound old $table table, upgrading it to contain 'urlhash' field...";
+ // We have to create a urlhash that is _not_ the primary key,
+ // transfer data and THEN run checkSchema
+ $schemadef['fields']['urlhash'] = array (
+ 'type' => 'varchar',
+ 'length' => 64,
+ 'not null' => true,
+ 'description' => 'sha256 hash of the URL',
+ );
+ $schemadef['fields']['url'] = array (
+ 'type' => 'text',
+ 'description' => 'short URL (or any other kind of redirect) for file (id)',
+ );
+ unset($schemadef['primary key']);
+ $schema->ensureTable($table, $schemadef);
+ echo "DONE.\n";
+
+ $classname = ucfirst($table);
+ $tablefix = new $classname;
+ // urlhash is hash('sha256', $url) in the File table
+ echo "Updating urlhash fields in $table table...";
+ // Maybe very MySQL specific :(
+ $tablefix->query(sprintf('UPDATE %1$s SET %2$s=%3$s;',
+ $schema->quoteIdentifier($table),
+ 'urlhash',
+ // The line below is "result of sha256 on column `url`"
+ 'SHA2(url, 256)'));
+ echo "DONE.\n";
+ echo "Resuming core schema upgrade...";
+ }
}
{
public $__table = 'file_thumbnail'; // table name
public $file_id; // int(4) primary_key not_null
- public $url; // varchar(255) unique_key
- public $filename; // varchar(255)
+ public $url; // text
+ public $filename; // varchar(191) not 255 because utf8mb4 takes more space
public $width; // int(4) primary_key
public $height; // int(4) primary_key
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
return array(
'fields' => array(
'file_id' => array('type' => 'int', 'not null' => true, 'description' => 'thumbnail for what URL/file'),
- 'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL of thumbnail'),
- 'filename' => array('type' => 'varchar', 'length' => 255, 'description' => 'if stored locally, filename is put here'),
+ 'url' => array('type' => 'text', 'description' => 'URL of thumbnail'),
+ 'filename' => array('type' => 'varchar', 'length' => 191, 'description' => 'if stored locally, filename is put here'),
'width' => array('type' => 'int', 'description' => 'width of thumbnail'),
'height' => array('type' => 'int', 'description' => 'height of thumbnail'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
public function getPath()
{
- return self::path($this->filename);
+ $filepath = self::path($this->filename);
+ if (!file_exists($filepath)) {
+ throw new FileNotFoundException($filepath);
+ }
+ return $filepath;
}
public function getUrl()
public $user_id; // int(4) primary_key not_null
public $foreign_id; // bigint(8) primary_key not_null unsigned
public $service; // int(4) primary_key not_null
- public $credentials; // varchar(255)
+ public $credentials; // varchar(191) not 255 because utf8mb4 takes more space
public $noticesync; // tinyint(1) not_null default_1
public $friendsync; // tinyint(1) not_null default_2
public $profilesync; // tinyint(1) not_null default_1
'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'link to user on this system, if exists'),
'foreign_id' => array('type' => 'int', 'size' => 'big', 'unsigned' => true, 'not null' => true, 'description' => 'link to user on foreign service, if exists'),
'service' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to service'),
- 'credentials' => array('type' => 'varchar', 'length' => 255, 'description' => 'authc credentials, typically a password'),
+ 'credentials' => array('type' => 'varchar', 'length' => 191, 'description' => 'authc credentials, typically a password'),
'noticesync' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 1, 'description' => 'notice synchronization, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies'),
'friendsync' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 2, 'description' => 'friend synchronization, bit 1 = sync outgoing, bit 2 = sync incoming'),
'profilesync' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 1, 'description' => 'profile synchronization, bit 1 = sync outgoing, bit 2 = sync incoming'),
public $__table = 'foreign_service'; // table name
public $id; // int(4) primary_key not_null
public $name; // varchar(32) unique_key not_null
- public $description; // varchar(255)
+ public $description; // varchar(191) not 255 because utf8mb4 takes more space
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
'fields' => array(
'id' => array('type' => 'int', 'not null' => true, 'description' => 'numeric key for service'),
'name' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'name of the service'),
- 'description' => array('type' => 'varchar', 'length' => 255, 'description' => 'description'),
+ 'description' => array('type' => 'varchar', 'length' => 191, 'description' => 'description'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
public $__table = 'foreign_user'; // table name
public $id; // bigint(8) primary_key not_null
public $service; // int(4) primary_key not_null
- public $uri; // varchar(255) unique_key not_null
- public $nickname; // varchar(255)
+ public $uri; // varchar(191) unique_key not_null not 255 because utf8mb4 takes more space
+ public $nickname; // varchar(191) not 255 because utf8mb4 takes more space
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
'fields' => array(
'id' => array('type' => 'int', 'size' => 'big', 'not null' => true, 'description' => 'unique numeric key on foreign service'),
'service' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to service'),
- 'uri' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'identifying URI'),
- 'nickname' => array('type' => 'varchar', 'length' => 255, 'description' => 'nickname on foreign service'),
+ 'uri' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'identifying URI'),
+ 'nickname' => array('type' => 'varchar', 'length' => 191, 'description' => 'nickname on foreign service'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
public $group_id; // int(4) primary_key not_null
public $profile_id; // int(4) primary_key not_null
public $is_admin; // tinyint(1)
- public $uri; // varchar(255)
+ public $uri; // varchar(191) not 255 because utf8mb4 takes more space
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
'group_id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to user_group'),
'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to profile table'),
'is_admin' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'is this user an admin?'),
- 'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universal identifier'),
+ 'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universal identifier'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
public $__table = 'invitation'; // table name
public $code; // varchar(32) primary_key not_null
public $user_id; // int(4) not_null
- public $address; // varchar(255) multiple_key not_null
+ public $address; // varchar(191) multiple_key not_null not 255 because utf8mb4 takes more space
public $address_type; // varchar(8) multiple_key not_null
public $registered_user_id; // int(4) not_null
public $created; // datetime() not_null
'fields' => array(
'code' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'random code for an invitation'),
'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'who sent the invitation'),
- 'address' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'invitation sent to'),
+ 'address' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'invitation sent to'),
'address_type' => array('type' => 'varchar', 'length' => 8, 'not null' => true, 'description' => 'address type ("email", "xmpp", "sms")'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'registered_user_id' => array('type' => 'int', 'not null' => false, 'description' => 'if the invitation is converted, who the new user is'),
public $__table = 'location_namespace'; // table name
public $id; // int(4) primary_key not_null
- public $description; // varchar(255)
+ public $description; // varchar(191)
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
return array(
'fields' => array(
'id' => array('type' => 'int', 'not null' => true, 'description' => 'identity for this namespace'),
- 'description' => array('type' => 'varchar', 'length' => 255, 'description' => 'description of the namespace'),
+ 'description' => array('type' => 'varchar', 'length' => 191, 'description' => 'description of the namespace'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date the record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
return $ckeys;
}
+ public function escapedTableName()
+ {
+ return common_database_tablename($this->tableName());
+ }
+
/**
* Returns an ID, checked that it is set and reasonably valid
*
// @FIXME return true only if something changed (otherwise 0)
return $result;
}
+
+ static public function beforeSchemaUpdate()
+ {
+ // NOOP
+ }
}
return $string;
}
- // We overload so that 'SET NAMES "utf8"' is called for
+ // We overload so that 'SET NAMES "utf8mb4"' is called for
// each connection
function _connect()
$conn = $DB->connection;
if (!empty($conn)) {
if ($DB instanceof DB_mysqli || $DB instanceof MDB2_Driver_mysqli) {
- mysqli_set_charset($conn, 'utf8');
+ mysqli_set_charset($conn, 'utf8mb4');
} else if ($DB instanceof DB_mysql || $DB instanceof MDB2_Driver_mysql) {
- mysql_set_charset('utf8', $conn);
+ mysql_set_charset('utf8mb4', $conn);
}
}
}
/* the code below is auto generated do not remove the above tag */
public $__table = 'nonce'; // table name
- public $consumer_key; // varchar(255) primary_key not_null
+ public $consumer_key; // varchar(191) primary_key not_null not 255 because utf8mb4 takes more space
public $tok; // char(32)
public $nonce; // char(32) primary_key not_null
public $ts; // datetime() primary_key not_null
return array(
'description' => 'OAuth nonce record',
'fields' => array(
- 'consumer_key' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'unique identifier, root URL'),
+ 'consumer_key' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'unique identifier, root URL'),
'tok' => array('type' => 'char', 'length' => 32, 'description' => 'buggy old value, ignored'),
'nonce' => array('type' => 'char', 'length' => 32, 'not null' => true, 'description' => 'nonce'),
'ts' => array('type' => 'datetime', 'not null' => true, 'description' => 'timestamp sent'),
public $__table = 'notice'; // table name
public $id; // int(4) primary_key not_null
public $profile_id; // int(4) multiple_key not_null
- public $uri; // varchar(255) unique_key
+ public $uri; // varchar(191) unique_key not 255 because utf8mb4 takes more space
public $content; // text
public $rendered; // text
- public $url; // varchar(255)
+ public $url; // varchar(191) not 255 because utf8mb4 takes more space
public $created; // datetime multiple_key not_null default_0000-00-00%2000%3A00%3A00
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
public $reply_to; // int(4)
public $location_id; // int(4)
public $location_ns; // int(4)
public $repeat_of; // int(4)
- public $verb; // varchar(255)
- public $object_type; // varchar(255)
+ public $verb; // varchar(191) not 255 because utf8mb4 takes more space
+ public $object_type; // varchar(191) not 255 because utf8mb4 takes more space
public $scope; // int(4)
/* the code above is auto generated do not remove the tag below */
'fields' => array(
'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'),
'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'who made the update'),
- 'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier, usually a tag URI'),
+ 'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier, usually a tag URI'),
'content' => array('type' => 'text', 'description' => 'update content', 'collate' => 'utf8_general_ci'),
'rendered' => array('type' => 'text', 'description' => 'HTML version of the content'),
- 'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL of any attachment (image, video, bookmark, whatever)'),
+ 'url' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL of any attachment (image, video, bookmark, whatever)'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
'reply_to' => array('type' => 'int', 'description' => 'notice replied to (usually a guess)'),
'location_id' => array('type' => 'int', 'description' => 'location id if possible'),
'location_ns' => array('type' => 'int', 'description' => 'namespace for location'),
'repeat_of' => array('type' => 'int', 'description' => 'notice this is a repeat of'),
- 'object_type' => array('type' => 'varchar', 'length' => 255, 'description' => 'URI representing activity streams object type', 'default' => 'http://activitystrea.ms/schema/1.0/note'),
- 'verb' => array('type' => 'varchar', 'length' => 255, 'description' => 'URI representing activity streams verb', 'default' => 'http://activitystrea.ms/schema/1.0/post'),
+ 'object_type' => array('type' => 'varchar', 'length' => 191, 'description' => 'URI representing activity streams object type', 'default' => 'http://activitystrea.ms/schema/1.0/note'),
+ 'verb' => array('type' => 'varchar', 'length' => 191, 'description' => 'URI representing activity streams verb', 'default' => 'http://activitystrea.ms/schema/1.0/post'),
'scope' => array('type' => 'int',
'description' => 'bit map for distribution scope; 0 = everywhere; 1 = this server only; 2 = addressees; 4 = followers; null = default'),
),
return $def;
}
-
+
/* Notice types */
const LOCAL_PUBLIC = 1;
const REMOTE = 0;
const FOLLOWER_SCOPE = 8;
protected $_profile = array();
-
+
/**
* Will always return a profile, if anything fails it will
* (through _setProfile) throw a NoProfileException.
}
return $this->_profile[$this->profile_id];
}
-
+
public function _setProfile(Profile $profile=null)
{
if (!$profile instanceof Profile) {
}
return $title;
}
-
+
public function getContent()
{
return $this->content;
$notice->insert(); // throws exception on failure
// If it's not part of a conversation, it's
// the beginning of a new conversation.
- if (empty($notice->conversation)) {
+ if (empty($notice->conversation)) {
$orig = clone($notice);
// $act->context->conversation will be null if it was not provided
$conv = Conversation::create($notice, $options['conversation']);
'distribute' => true);
// options will have default values when nothing has been supplied
- $options = array_merge($defaults, $options);
+ $options = array_merge($defaults, $options);
foreach (array_keys($defaults) as $key) {
// Only convert the keynames we specify ourselves from 'defaults' array into variables
$$key = $options[$key];
// Prepare inbox delivery, may be queued to background.
$stored->distribute();
}
-
+
return $stored;
}
}
$args = func_get_args();
-
$format = array_shift($args);
-
$keyPart = vsprintf($format, $args);
-
$cacheKey = Cache::key($keyPart);
-
$c->delete($cacheKey);
// delete the "last" stream, too, if this notice is
}
protected $_attachments = array();
-
+
function attachments() {
if (isset($this->_attachments[$this->id])) {
return $this->_attachments[$this->id];
}
-
+
$f2ps = File_to_post::listGet('post_id', array($this->id));
-
$ids = array();
-
foreach ($f2ps[$this->id] as $f2p) {
- $ids[] = $f2p->file_id;
+ $ids[] = $f2p->file_id;
}
-
- $files = File::multiGet('id', $ids);
+ $files = File::multiGet('id', $ids);
$this->_attachments[$this->id] = $files->fetchAll();
-
return $this->_attachments[$this->id];
}
$root->free();
return $root;
}
-
+
if (is_null($profile)) {
$keypart = sprintf('notice:conversation_root:%d:null', $this->id);
} else {
$this->id,
$profile->id);
}
-
+
$root = self::cacheGet($keypart);
if ($root !== false && $root->inScope($profile)) {
function getReplyProfiles()
{
$ids = $this->getReplies();
-
+
$profiles = Profile::multiGet('id', $ids);
-
+
return $profiles->fetchAll();
}
*
* @return array of Group objects
*/
-
+
protected $_groups = array();
-
+
function getGroups()
{
// Don't save groups for repeats
if (!empty($this->repeat_of)) {
return array();
}
-
+
if (isset($this->_groups[$this->id])) {
return $this->_groups[$this->id];
}
-
+
$gis = Group_inbox::listGet('notice_id', array($this->id));
$ids = array();
- foreach ($gis[$this->id] as $gi)
- {
+ foreach ($gis[$this->id] as $gi) {
$ids[] = $gi->group_id;
}
-
+
$groups = User_group::multiGet('id', $ids);
-
$this->_groups[$this->id] = $groups->fetchAll();
-
return $this->_groups[$this->id];
}
-
+
function _setGroups($groups)
{
$this->_groups[$this->id] = $groups;
// Unfortunately this is likely to lose tags or URLs
// at the end of long notices.
$content = mb_substr($content, 0, $maxlen - 4) . ' ...';
- }
+ }
// Scope is same as this one's
$scope = self::defaultScope();
}
- // If there's no scope, anyone (even anon) is in scope.
-
- if ($scope == 0) { // Not private
-
+ if ($scope == 0 && !$this->getProfile()->isPrivateStream()) { // Not scoping, so it is public.
return !$this->isHiddenSpam($profile);
+ }
- } else { // Private, somehow
-
- // If there's scope, anon cannot be in scope
+ // If there's scope, anon cannot be in scope
+ if (empty($profile)) {
+ return false;
+ }
- if (empty($profile)) {
- return false;
- }
+ // Author is always in scope
+ if ($this->profile_id == $profile->id) {
+ return true;
+ }
- // Author is always in scope
+ // Only for users on this site
+ if (($scope & Notice::SITE_SCOPE) && !$profile->isLocal()) {
+ return false;
+ }
- if ($this->profile_id == $profile->id) {
- return true;
- }
+ // Only for users mentioned in the notice
+ if ($scope & Notice::ADDRESSEE_SCOPE) {
- // Only for users on this site
+ $reply = Reply::pkeyGet(array('notice_id' => $this->id,
+ 'profile_id' => $profile->id));
- if (($scope & Notice::SITE_SCOPE) && !$profile->isLocal()) {
+ if (!$reply instanceof Reply) {
return false;
}
+ }
- // Only for users mentioned in the notice
-
- if ($scope & Notice::ADDRESSEE_SCOPE) {
-
- $reply = Reply::pkeyGet(array('notice_id' => $this->id,
- 'profile_id' => $profile->id));
-
- if (!$reply instanceof Reply) {
- return false;
- }
- }
-
- // Only for members of the given group
-
- if ($scope & Notice::GROUP_SCOPE) {
+ // Only for members of the given group
+ if ($scope & Notice::GROUP_SCOPE) {
- // XXX: just query for the single membership
+ // XXX: just query for the single membership
- $groups = $this->getGroups();
+ $groups = $this->getGroups();
- $foundOne = false;
+ $foundOne = false;
- foreach ($groups as $group) {
- if ($profile->isMember($group)) {
- $foundOne = true;
- break;
- }
- }
-
- if (!$foundOne) {
- return false;
+ foreach ($groups as $group) {
+ if ($profile->isMember($group)) {
+ $foundOne = true;
+ break;
}
}
- // Only for followers of the author
-
- $author = null;
+ if (!$foundOne) {
+ return false;
+ }
+ }
- if ($scope & Notice::FOLLOWER_SCOPE) {
+ if ($scope & Notice::FOLLOWER_SCOPE || $this->getProfile()->isPrivateStream()) {
- try {
- $author = $this->getProfile();
- } catch (Exception $e) {
- return false;
- }
-
- if (!Subscription::exists($profile, $author)) {
- return false;
- }
+ if (!Subscription::exists($profile, $this->getProfile())) {
+ return false;
}
-
- return !$this->isHiddenSpam($profile);
}
+
+ return !$this->isHiddenSpam($profile);
}
function isHiddenSpam($profile) {
-
+
// Hide posts by silenced users from everyone but moderators.
if (common_config('notice', 'hidespam')) {
$skip = array('_profile', '_groups', '_attachments', '_faves', '_replies', '_repeats');
return array_diff($vars, $skip);
}
-
+
static function defaultScope()
{
$scope = common_config('notice', 'defaultscope');
static function fillProfiles($notices)
{
$map = self::getProfiles($notices);
-
foreach ($notices as $entry=>$notice) {
try {
if (array_key_exists($notice->profile_id, $map)) {
unset($notices[$entry]);
}
}
-
+
return array_values($map);
}
-
+
static function getProfiles(&$notices)
{
$ids = array();
foreach ($notices as $notice) {
$ids[] = $notice->profile_id;
}
-
$ids = array_unique($ids);
-
- return Profile::pivotGet('id', $ids);
+ return Profile::pivotGet('id', $ids);
}
-
+
static function fillGroups(&$notices)
{
$ids = self::_idsOf($notices);
-
$gis = Group_inbox::listGet('notice_id', $ids);
-
$gids = array();
- foreach ($gis as $id => $gi)
- {
+ foreach ($gis as $id => $gi) {
foreach ($gi as $g)
{
$gids[] = $g->group_id;
}
}
-
+
$gids = array_unique($gids);
-
$group = User_group::pivotGet('id', $gids);
-
foreach ($notices as $notice)
{
$grps = array();
static function fillAttachments(&$notices)
{
$ids = self::_idsOf($notices);
-
$f2pMap = File_to_post::listGet('post_id', $ids);
-
$fileIds = array();
-
foreach ($f2pMap as $noticeId => $f2ps) {
foreach ($f2ps as $f2p) {
- $fileIds[] = $f2p->file_id;
+ $fileIds[] = $f2p->file_id;
}
}
$fileIds = array_unique($fileIds);
-
$fileMap = File::pivotGet('id', $fileIds);
-
foreach ($notices as $notice)
{
$files = array();
public $__table = 'notice_source'; // table name
public $code; // varchar(32) primary_key not_null
- public $name; // varchar(255) not_null
- public $url; // varchar(255) not_null
+ public $name; // varchar(191) not_null not 255 because utf8mb4 takes more space
+ public $url; // varchar(191) not_null not 255 because utf8mb4 takes more space
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
return array(
'fields' => array(
'code' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'source code'),
- 'name' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'name of the source'),
- 'url' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'url to link to'),
+ 'name' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'name of the source'),
+ 'url' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'url to link to'),
'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'date this record was created'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
public $__table = 'oauth_application'; // table name
public $id; // int(4) primary_key not_null
public $owner; // int(4) not_null
- public $consumer_key; // varchar(255) not_null
- public $name; // varchar(255) not_null
- public $description; // varchar(255)
- public $icon; // varchar(255) not_null
- public $source_url; // varchar(255)
- public $organization; // varchar(255)
- public $homepage; // varchar(255)
- public $callback_url; // varchar(255) not_null
+ public $consumer_key; // varchar(191) not_null not 255 because utf8mb4 takes more space
+ public $name; // varchar(191) not_null not 255 because utf8mb4 takes more space
+ public $description; // varchar(191) not 255 because utf8mb4 takes more space
+ public $icon; // varchar(191) not_null not 255 because utf8mb4 takes more space
+ public $source_url; // varchar(191) not 255 because utf8mb4 takes more space
+ public $organization; // varchar(191) not 255 because utf8mb4 takes more space
+ public $homepage; // varchar(191) not 255 because utf8mb4 takes more space
+ public $callback_url; // varchar(191) not_null not 255 because utf8mb4 takes more space
public $type; // tinyint(1)
public $access_type; // tinyint(1)
public $created; // datetime not_null
static function maxDesc()
{
// This used to default to textlimit or allow unlimited descriptions,
- // but this isn't part of a notice and the field's limited to 255 chars
- // in the DB, so those seem silly.
+ // but this isn't part of a notice and the field's limited to 191 chars
+ // in the DB, so those seem silly. (utf8mb4 takes up more space, so can't use 255)
//
- // Now just defaulting to 255 max unless a smaller application desclimit
+ // Now just defaulting to 191 max unless a smaller application desclimit
// is actually set. Setting to 0 will use the maximum.
- $max = 255;
+ $max = 191;
$desclimit = intval(common_config('application', 'desclimit'));
if ($desclimit > 0 && $desclimit < $max) {
return $desclimit;
'fields' => array(
'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'),
'owner' => array('type' => 'int', 'not null' => true, 'description' => 'owner of the application'),
- 'consumer_key' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'application consumer key'),
- 'name' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'name of the application'),
- 'description' => array('type' => 'varchar', 'length' => 255, 'description' => 'description of the application'),
- 'icon' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'application icon'),
- 'source_url' => array('type' => 'varchar', 'length' => 255, 'description' => 'application homepage - used for source link'),
- 'organization' => array('type' => 'varchar', 'length' => 255, 'description' => 'name of the organization running the application'),
- 'homepage' => array('type' => 'varchar', 'length' => 255, 'description' => 'homepage for the organization'),
- 'callback_url' => array('type' => 'varchar', 'length' => 255, 'description' => 'url to redirect to after authentication'),
+ 'consumer_key' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'application consumer key'),
+ 'name' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'name of the application'),
+ 'description' => array('type' => 'varchar', 'length' => 191, 'description' => 'description of the application'),
+ 'icon' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'application icon'),
+ 'source_url' => array('type' => 'varchar', 'length' => 191, 'description' => 'application homepage - used for source link'),
+ 'organization' => array('type' => 'varchar', 'length' => 191, 'description' => 'name of the organization running the application'),
+ 'homepage' => array('type' => 'varchar', 'length' => 191, 'description' => 'homepage for the organization'),
+ 'callback_url' => array('type' => 'varchar', 'length' => 191, 'description' => 'url to redirect to after authentication'),
'type' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'type of app, 1 = browser, 2 = desktop'),
'access_type' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'default access type, bit 1 = read, bit 2 = write'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
public $profile_id; // int(4) primary_key not_null
public $application_id; // int(4) primary_key not_null
public $access_type; // tinyint(1)
- public $token; // varchar(255)
+ public $token; // varchar(191) not 255 because utf8mb4 takes more space
public $created; // datetime not_null
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'user of the application'),
'application_id' => array('type' => 'int', 'not null' => true, 'description' => 'id of the application'),
'access_type' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'access type, bit 1 = read, bit 2 = write'),
- 'token' => array('type' => 'varchar', 'length' => 255, 'description' => 'request or access token'),
+ 'token' => array('type' => 'varchar', 'length' => 191, 'description' => 'request or access token'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
public $__table = 'oauth_token_association'; // table name
public $profile_id; // int(4) primary_key not_null
public $application_id; // int(4) primary_key not_null
- public $token; // varchar(255) primary key not null
+ public $token; // varchar(191) primary key not null not 255 because utf8mb4 takes more space
public $created; // datetime not_null
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
'fields' => array(
'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'associated user'),
'application_id' => array('type' => 'int', 'not null' => true, 'description' => 'the application'),
- 'token' => array('type' => 'varchar', 'length' => '255', 'not null' => true, 'description' => 'token used for this association'),
+ 'token' => array('type' => 'varchar', 'length' => '191', 'not null' => true, 'description' => 'token used for this association'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
public $__table = 'profile'; // table name
public $id; // int(4) primary_key not_null
public $nickname; // varchar(64) multiple_key not_null
- public $fullname; // varchar(255) multiple_key
- public $profileurl; // varchar(255)
- public $homepage; // varchar(255) multiple_key
+ public $fullname; // varchar(191) multiple_key not 255 because utf8mb4 takes more space
+ public $profileurl; // varchar(191) not 255 because utf8mb4 takes more space
+ public $homepage; // varchar(191) multiple_key not 255 because utf8mb4 takes more space
public $bio; // text() multiple_key
- public $location; // varchar(255) multiple_key
+ public $location; // varchar(191) multiple_key not 255 because utf8mb4 takes more space
public $lat; // decimal(10,7)
public $lon; // decimal(10,7)
public $location_id; // int(4)
'fields' => array(
'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'),
'nickname' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'nickname or username', 'collate' => 'utf8_general_ci'),
- 'fullname' => array('type' => 'varchar', 'length' => 255, 'description' => 'display name', 'collate' => 'utf8_general_ci'),
- 'profileurl' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL, cached so we dont regenerate'),
- 'homepage' => array('type' => 'varchar', 'length' => 255, 'description' => 'identifying URL', 'collate' => 'utf8_general_ci'),
+ 'fullname' => array('type' => 'varchar', 'length' => 191, 'description' => 'display name', 'collate' => 'utf8_general_ci'),
+ 'profileurl' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL, cached so we dont regenerate'),
+ 'homepage' => array('type' => 'varchar', 'length' => 191, 'description' => 'identifying URL', 'collate' => 'utf8_general_ci'),
'bio' => array('type' => 'text', 'description' => 'descriptive biography', 'collate' => 'utf8_general_ci'),
- 'location' => array('type' => 'varchar', 'length' => 255, 'description' => 'physical location', 'collate' => 'utf8_general_ci'),
+ 'location' => array('type' => 'varchar', 'length' => 191, 'description' => 'physical location', 'collate' => 'utf8_general_ci'),
'lat' => array('type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'latitude'),
'lon' => array('type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'longitude'),
'location_id' => array('type' => 'int', 'description' => 'location id if possible'),
return $feed;
}
+ public function repeatedToMe($offset=0, $limit=20, $since_id=null, $max_id=null)
+ {
+ // TRANS: Exception thrown when trying view "repeated to me".
+ throw new Exception(_('Not implemented since inbox change.'));
+ }
+
/*
* Get a Profile object by URI. Will call external plugins for help
* using the event StartGetProfileFromURI.
return $this->getUser()->shortenLinks($text, $always);
}
+ public function isPrivateStream()
+ {
+ // We only know of public remote users as of yet...
+ if (!$this->isLocal()) {
+ return false;
+ }
+ return $this->getUser()->private_stream ? true : false;
+ }
+
public function delPref($namespace, $topic) {
return Profile_prefs::setData($this, $namespace, $topic, null);
}
public $private; // tinyint(1)
public $created; // datetime not_null default_0000-00-00%2000%3A00%3A00
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
- public $uri; // varchar(255) unique_key
- public $mainpage; // varchar(255)
+ public $uri; // varchar(191) unique_key not 255 because utf8mb4 takes more space
+ public $mainpage; // varchar(191) not 255 because utf8mb4 takes more space
public $tagged_count; // smallint
public $subscriber_count; // smallint
'created' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date the tag was added'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date the tag was modified'),
- 'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universal identifier'),
- 'mainpage' => array('type' => 'varchar', 'length' => 255, 'description' => 'page to link to'),
+ 'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universal identifier'),
+ 'mainpage' => array('type' => 'varchar', 'length' => 191, 'description' => 'page to link to'),
'tagged_count' => array('type' => 'int', 'default' => 0, 'description' => 'number of people tagged with this tag by this user'),
'subscriber_count' => array('type' => 'int', 'default' => 0, 'description' => 'number of subscribers to this tag'),
),
{
public $__table = 'profile_prefs'; // table name
public $profile_id; // int(4) primary_key not_null
- public $namespace; // varchar(255) not_null
- public $topic; // varchar(255) not_null
+ public $namespace; // varchar(191) not_null
+ public $topic; // varchar(191) not_null
public $data; // text
public $created; // datetime not_null default_0000-00-00%2000%3A00%3A00
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
return array(
'fields' => array(
'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'user'),
- 'namespace' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'namespace, like pluginname or category'),
- 'topic' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'preference key, i.e. description, age...'),
+ 'namespace' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'namespace, like pluginname or category'),
+ 'topic' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'preference key, i.e. description, age...'),
'data' => array('type' => 'blob', 'description' => 'topic data, may be anything'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
public $__table = 'sms_carrier'; // table name
public $id; // int(4) primary_key not_null
public $name; // varchar(64) unique_key
- public $email_pattern; // varchar(255) not_null
+ public $email_pattern; // varchar(191) not_null not 255 because utf8mb4 takes more space
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
'fields' => array(
'id' => array('type' => 'int', 'not null' => true, 'description' => 'primary key for SMS carrier'),
'name' => array('type' => 'varchar', 'length' => 64, 'description' => 'name of the carrier'),
- 'email_pattern' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'sprintf pattern for making an email address from a phone number'),
+ 'email_pattern' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'sprintf pattern for making an email address from a phone number'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
public $__table = 'status_network'; // table name
public $site_id; // int(4) primary_key not_null
public $nickname; // varchar(64) unique_key not_null
- public $hostname; // varchar(255) unique_key
- public $pathname; // varchar(255) unique_key
- public $dbhost; // varchar(255)
- public $dbuser; // varchar(255)
- public $dbpass; // varchar(255)
- public $dbname; // varchar(255)
- public $sitename; // varchar(255)
- public $theme; // varchar(255)
- public $logo; // varchar(255)
+ public $hostname; // varchar(191) unique_key not 255 because utf8mb4 takes more space
+ public $pathname; // varchar(191) unique_key not 255 because utf8mb4 takes more space
+ public $dbhost; // varchar(191) not 255 because utf8mb4 takes more space
+ public $dbuser; // varchar(191) not 255 because utf8mb4 takes more space
+ public $dbpass; // varchar(191) not 255 because utf8mb4 takes more space
+ public $dbname; // varchar(191) not 255 because utf8mb4 takes more space
+ public $sitename; // varchar(191) not 255 because utf8mb4 takes more space
+ public $theme; // varchar(191) not 255 because utf8mb4 takes more space
+ public $logo; // varchar(191) not 255 because utf8mb4 takes more space
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
public $subscribed; // int(4) primary_key not_null
public $jabber; // tinyint(1) default_1
public $sms; // tinyint(1) default_1
- public $token; // varchar(255)
- public $secret; // varchar(255)
- public $uri; // varchar(255)
+ public $token; // varchar(191) not 255 because utf8mb4 takes more space
+ public $secret; // varchar(191) not 255 because utf8mb4 takes more space
+ public $uri; // varchar(191) not 255 because utf8mb4 takes more space
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
'subscribed' => array('type' => 'int', 'not null' => true, 'description' => 'profile being listened to'),
'jabber' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'deliver jabber messages'),
'sms' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'deliver sms messages'),
- 'token' => array('type' => 'varchar', 'length' => 255, 'description' => 'authorization token'),
- 'secret' => array('type' => 'varchar', 'length' => 255, 'description' => 'token secret'),
- 'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier'),
+ 'token' => array('type' => 'varchar', 'length' => 191, 'description' => 'authorization token'),
+ 'secret' => array('type' => 'varchar', 'length' => 191, 'description' => 'token secret'),
+ 'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
static function exists(Profile $subscriber, Profile $other)
{
- $sub = Subscription::pkeyGet(array('subscriber' => $subscriber->id,
- 'subscribed' => $other->id));
- return ($sub instanceof Subscription);
+ try {
+ $sub = self::getSubscription($subscriber, $other);
+ } catch (NoResultException $e) {
+ return false;
+ }
+
+ return true;
+ }
+
+ static function getSubscription(Profile $subscriber, Profile $other)
+ {
+ // This is essentially a pkeyGet but we have an object to return in NoResultException
+ $sub = new Subscription();
+ $sub->subscriber = $subscriber->id;
+ $sub->subscribed = $other->id;
+ if (!$sub->find(true)) {
+ throw new NoResultException($sub);
+ }
+ return $sub;
}
function asActivity()
/* the code below is auto generated do not remove the above tag */
public $__table = 'token'; // table name
- public $consumer_key; // varchar(255) primary_key not_null
+ public $consumer_key; // varchar(191) primary_key not_null not 255 because utf8mb4 takes more space
public $tok; // char(32) primary_key not_null
public $secret; // char(32) not_null
public $type; // tinyint(1) not_null
public $state; // tinyint(1)
- public $verifier; // varchar(255)
- public $verified_callback; // varchar(255)
+ public $verifier; // varchar(191) not 255 because utf8mb4 takes more space
+ public $verified_callback; // varchar(191) not 255 because utf8mb4 takes more space
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
return array(
'description' => 'OAuth token record',
'fields' => array(
- 'consumer_key' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'unique identifier, root URL'),
+ 'consumer_key' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'unique identifier, root URL'),
'tok' => array('type' => 'char', 'length' => 32, 'not null' => true, 'description' => 'identifying value'),
'secret' => array('type' => 'char', 'length' => 32, 'not null' => true, 'description' => 'secret value'),
'type' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 0, 'description' => 'request or access'),
'state' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'for requests, 0 = initial, 1 = authorized, 2 = used'),
- 'verifier' => array('type' => 'varchar', 'length' => 255, 'description' => 'verifier string for OAuth 1.0a'),
- 'verified_callback' => array('type' => 'varchar', 'length' => 255, 'description' => 'verified callback URL for OAuth 1.0a'),
+ 'verifier' => array('type' => 'varchar', 'length' => 191, 'description' => 'verifier string for OAuth 1.0a'),
+ 'verified_callback' => array('type' => 'varchar', 'length' => 191, 'description' => 'verified callback URL for OAuth 1.0a'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
public $__table = 'user'; // table name
public $id; // int(4) primary_key not_null
public $nickname; // varchar(64) unique_key
- public $password; // varchar(255)
- public $email; // varchar(255) unique_key
- public $incomingemail; // varchar(255) unique_key
+ public $password; // varchar(191) not 255 because utf8mb4 takes more space
+ public $email; // varchar(191) unique_key not 255 because utf8mb4 takes more space
+ public $incomingemail; // varchar(191) unique_key not 255 because utf8mb4 takes more space
public $emailnotifysub; // tinyint(1) default_1
public $emailnotifyfav; // tinyint(1) default_1
public $emailnotifynudge; // tinyint(1) default_1
public $carrier; // int(4)
public $smsnotify; // tinyint(1)
public $smsreplies; // tinyint(1)
- public $smsemail; // varchar(255)
- public $uri; // varchar(255) unique_key
+ public $smsemail; // varchar(191) not 255 because utf8mb4 takes more space
+ public $uri; // varchar(191) unique_key not 255 because utf8mb4 takes more space
public $autosubscribe; // tinyint(1)
public $subscribe_policy; // tinyint(1)
public $urlshorteningservice; // varchar(50) default_ur1.ca
'fields' => array(
'id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to profile table'),
'nickname' => array('type' => 'varchar', 'length' => 64, 'description' => 'nickname or username, duped in profile'),
- 'password' => array('type' => 'varchar', 'length' => 255, 'description' => 'salted password, can be null for OpenID users'),
- 'email' => array('type' => 'varchar', 'length' => 255, 'description' => 'email address for password recovery etc.'),
- 'incomingemail' => array('type' => 'varchar', 'length' => 255, 'description' => 'email address for post-by-email'),
+ 'password' => array('type' => 'varchar', 'length' => 191, 'description' => 'salted password, can be null for OpenID users'),
+ 'email' => array('type' => 'varchar', 'length' => 191, 'description' => 'email address for password recovery etc.'),
+ 'incomingemail' => array('type' => 'varchar', 'length' => 191, 'description' => 'email address for post-by-email'),
'emailnotifysub' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'Notify by email of subscriptions'),
'emailnotifyfav' => array('type' => 'int', 'size' => 'tiny', 'default' => null, 'description' => 'Notify by email of favorites'),
'emailnotifynudge' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'description' => 'Notify by email of nudges'),
'carrier' => array('type' => 'int', 'description' => 'foreign key to sms_carrier'),
'smsnotify' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'whether to send notices to SMS'),
'smsreplies' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'whether to send notices to SMS on replies'),
- 'smsemail' => array('type' => 'varchar', 'length' => 255, 'description' => 'built from sms and carrier'),
- 'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier, usually a tag URI'),
+ 'smsemail' => array('type' => 'varchar', 'length' => 191, 'description' => 'built from sms and carrier'),
+ 'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier, usually a tag URI'),
'autosubscribe' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'automatically subscribe to users who subscribe to us'),
'subscribe_policy' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => '0 = anybody can subscribe; 1 = require approval'),
'urlshorteningservice' => array('type' => 'varchar', 'length' => 50, 'default' => 'internal', 'description' => 'service to use for auto-shortening URLs'),
return $stream->getNotices($offset, $limit, $since_id, $max_id);
}
-
- function repeatedToMe($offset=0, $limit=20, $since_id=null, $max_id=null)
+ public function repeatedToMe($offset=0, $limit=20, $since_id=null, $max_id=null)
{
- // TRANS: Exception thrown when trying view "repeated to me".
- throw new Exception(_('Not implemented since inbox change.'));
+ return $this->getProfile()->repeatedToMe($offset, $limit, $since_id, $max_id);
}
public static function siteOwner()
return $act;
}
+ public function isPrivateStream()
+ {
+ return $this->getProfile()->isPrivateStream();
+ }
+
public function delPref($namespace, $topic)
{
return $this->getProfile()->delPref($namespace, $topic);
public $__table = 'user_group'; // table name
public $id; // int(4) primary_key not_null
public $nickname; // varchar(64)
- public $fullname; // varchar(255)
- public $homepage; // varchar(255)
+ public $fullname; // varchar(191) not 255 because utf8mb4 takes more space
+ public $homepage; // varchar(191) not 255 because utf8mb4 takes more space
public $description; // text
- public $location; // varchar(255)
- public $original_logo; // varchar(255)
- public $homepage_logo; // varchar(255)
- public $stream_logo; // varchar(255)
- public $mini_logo; // varchar(255)
+ public $location; // varchar(191) not 255 because utf8mb4 takes more space
+ public $original_logo; // varchar(191) not 255 because utf8mb4 takes more space
+ public $homepage_logo; // varchar(191) not 255 because utf8mb4 takes more space
+ public $stream_logo; // varchar(191) not 255 because utf8mb4 takes more space
+ public $mini_logo; // varchar(191) not 255 because utf8mb4 takes more space
public $created; // datetime not_null default_0000-00-00%2000%3A00%3A00
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
- public $uri; // varchar(255) unique_key
- public $mainpage; // varchar(255)
+ public $uri; // varchar(191) unique_key not 255 because utf8mb4 takes more space
+ public $mainpage; // varchar(191) not 255 because utf8mb4 takes more space
public $join_policy; // tinyint
public $force_scope; // tinyint
'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to profile table'),
'nickname' => array('type' => 'varchar', 'length' => 64, 'description' => 'nickname for addressing'),
- 'fullname' => array('type' => 'varchar', 'length' => 255, 'description' => 'display name'),
- 'homepage' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL, cached so we dont regenerate'),
+ 'fullname' => array('type' => 'varchar', 'length' => 191, 'description' => 'display name'),
+ 'homepage' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL, cached so we dont regenerate'),
'description' => array('type' => 'text', 'description' => 'group description'),
- 'location' => array('type' => 'varchar', 'length' => 255, 'description' => 'related physical location, if any'),
+ 'location' => array('type' => 'varchar', 'length' => 191, 'description' => 'related physical location, if any'),
- 'original_logo' => array('type' => 'varchar', 'length' => 255, 'description' => 'original size logo'),
- 'homepage_logo' => array('type' => 'varchar', 'length' => 255, 'description' => 'homepage (profile) size logo'),
- 'stream_logo' => array('type' => 'varchar', 'length' => 255, 'description' => 'stream-sized logo'),
- 'mini_logo' => array('type' => 'varchar', 'length' => 255, 'description' => 'mini logo'),
+ 'original_logo' => array('type' => 'varchar', 'length' => 191, 'description' => 'original size logo'),
+ 'homepage_logo' => array('type' => 'varchar', 'length' => 191, 'description' => 'homepage (profile) size logo'),
+ 'stream_logo' => array('type' => 'varchar', 'length' => 191, 'description' => 'stream-sized logo'),
+ 'mini_logo' => array('type' => 'varchar', 'length' => 191, 'description' => 'mini logo'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- 'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universal identifier'),
- 'mainpage' => array('type' => 'varchar', 'length' => 255, 'description' => 'page for group info to link to'),
+ 'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universal identifier'),
+ 'mainpage' => array('type' => 'varchar', 'length' => 191, 'description' => 'page for group info to link to'),
'join_policy' => array('type' => 'int', 'size' => 'tiny', 'description' => '0=open; 1=requires admin approval'),
'force_scope' => array('type' => 'int', 'size' => 'tiny', 'description' => '0=never,1=sometimes,-1=always'),
),
public $__table = 'user_im_prefs'; // table name
public $user_id; // int(4) primary_key not_null
- public $screenname; // varchar(255) not_null
- public $transport; // varchar(255) not_null
+ public $screenname; // varchar(191) not_null not 255 because utf8mb4 takes more space
+ public $transport; // varchar(191) not_null not 255 because utf8mb4 takes more space
public $notify; // tinyint(1)
public $replies; // tinyint(1)
public $microid; // tinyint(1)
return array(
'fields' => array(
'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user'),
- 'screenname' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'screenname on this service'),
- 'transport' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'transport (ex xmpp, aim)'),
+ 'screenname' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'screenname on this service'),
+ 'transport' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'transport (ex xmpp, aim)'),
'notify' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 0, 'description' => 'Notify when a new notice is sent'),
'replies' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 0, 'description' => 'Send replies from people not subscribed to'),
'microid' => array('type' => 'int', 'size' => 'tiny', 'not null' => true, 'default' => 1, 'description' => 'Publish a MicroID'),
public $__table = 'user_username'; // table name
public $user_id; // int(4) not_null
- public $provider_name; // varchar(255) primary_key not_null
- public $username; // varchar(255) primary_key not_null
+ public $provider_name; // varchar(191) primary_key not_null not 255 because utf8mb4 takes more space
+ public $username; // varchar(191) primary_key not_null not 255 because utf8mb4 takes more space
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
{
return array(
'fields' => array(
- 'provider_name' => array('type' => 'varchar', 'length' => 255, 'description' => 'provider name'),
- 'username' => array('type' => 'varchar', 'length' => 255, 'description' => 'username'),
+ 'provider_name' => array('type' => 'varchar', 'length' => 191, 'description' => 'provider name'),
+ 'username' => array('type' => 'varchar', 'length' => 191, 'description' => 'username'),
'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice id this title relates to'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
created datetime not null comment 'date this record was created',
modified timestamp comment 'date this record was modified'
-) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
create table status_network_tag (
site_id integer comment 'unique id',
constraint primary key (site_id, tag),
index status_network_tag_tag_idx (tag)
-) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
+) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
<li>
<label for="site_profile">Type of site</label>
<select id="site_profile" name="site_profile">
- <option value="private">Private</option>
<option value="community">Community</option>
- <option value ="public">Public</option>
- <option value ="singleuser">Single User</option>
+ <option value="public">Public (open registration)</option>
+ <option value="singleuser">Single User</option>
+ <option value="private">Private (no federation)</option>
</select>
<p class="form_guide">Initial access settings for your site</p>
</li>
});
},
- /**
- * Called when a people tag edit box is shown in the interface
- *
- * - loads the jQuery UI autocomplete plugin
- * - sets event handlers for tag completion
- *
- */
- PeopletagAutocomplete: function (txtBox) {
- var split = function (val) {
- return val.split( /\s+/ );
- }
- var extractLast = function (term) {
- return split(term).pop();
- }
-
- // don't navigate away from the field on tab when selecting an item
- txtBox.on( "keydown", function ( event ) {
- if ( event.keyCode === $.ui.keyCode.TAB &&
- $(this).data( "ui-autocomplete" ).menu.active ) {
- event.preventDefault();
- }
- }).autocomplete({
- minLength: 0,
- source: function (request, response) {
- // delegate back to autocomplete, but extract the last term
- response($.ui.autocomplete.filter(
- SN.C.PtagACData, extractLast(request.term)));
- },
- focus: function () {
- return false;
- },
- select: function (event, ui) {
- var terms = split(this.value);
- terms.pop();
- terms.push(ui.item.value);
- terms.push("");
- this.value = terms.join(" ");
- return false;
- }
- }).data('ui-autocomplete')._renderItem = function (ul, item) {
- // FIXME: with jQuery UI you cannot have it highlight the match
- var _l = '<a class="ptag-ac-line-tag">' + item.tag
- + ' <em class="privacy_mode">' + item.mode + '</em>'
- + '<span class="freq">' + item.freq + '</span></a>'
-
- return $("<li/>")
- .addClass('mode-' + item.mode)
- .addClass('ptag-ac-line')
- .data("item.autocomplete", item)
- .append(_l)
- .appendTo(ul);
- }
- },
-
/**
* Run setup for the ajax people tags editor
*
}
SN.C.PtagACData = data;
- SN.Init.PeopletagAutocomplete(form.find('#tags'));
}
});
// Get (safe!) HTML and text versions of the content
- $rendered = $this->purify($sourceContent);
+ $rendered = common_purify($sourceContent);
$content = common_strip_html($rendered);
$shortened = $user->shortenLinks($content);
return array($groups, $replies);
}
-
-
- function purify($content)
- {
- require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
-
- $config = array('safe' => 1,
- 'deny_attribute' => 'id,style,on*');
-
- return htmLawed($content, $config);
- }
}
$twitter_user['statuses_count'] = $profile->noticeCount();
// Is the requesting user following this user?
+ // These values might actually also mean "unknown". Ambiguity issues?
$twitter_user['following'] = false;
$twitter_user['statusnet_blocking'] = false;
$twitter_user['notifications'] = false;
- if (isset($this->auth_user)) {
-
- $twitter_user['following'] = $this->auth_user->isSubscribed($profile);
- $twitter_user['statusnet_blocking'] = $this->auth_user->hasBlocked($profile);
-
- // Notifications on?
- $sub = Subscription::pkeyGet(array('subscriber' =>
- $this->auth_user->id,
- 'subscribed' => $profile->id));
-
- if ($sub) {
+ if ($this->scoped instanceof Profile) {
+ try {
+ $sub = Subscription::getSubscription($this->scoped, $profile);
+ // Notifications on?
+ $twitter_user['following'] = true;
+ $twitter_user['statusnet_blocking'] = $this->scoped->hasBlocked($profile);
$twitter_user['notifications'] = ($sub->jabber || $sub->sms);
+ } catch (NoResultException $e) {
+ // well, the values are already false...
}
}
$twitter_group['nickname'] = $group->nickname;
$twitter_group['fullname'] = $group->fullname;
- if (isset($this->auth_user)) {
- $twitter_group['member'] = $this->auth_user->isMember($group);
+ if ($this->scoped instanceof Profile) {
+ $twitter_group['member'] = $this->scoped->isMember($group);
$twitter_group['blocked'] = Group_block::isBlocked(
$group,
- $this->auth_user->getProfile()
+ $this->scoped
);
}
$twitter_list['member_count'] = $list->taggedCount();
$twitter_list['uri'] = $list->getUri();
- if (isset($this->auth_user)) {
- $twitter_list['following'] = $list->hasSubscriber($this->auth_user);
+ if ($this->scoped instanceof Profile) {
+ $twitter_list['following'] = $list->hasSubscriber($this->scoped);
} else {
$twitter_list['following'] = false;
}
$relationship = array();
$relationship['source'] =
- $this->relationshipDetailsArray($source, $target);
+ $this->relationshipDetailsArray($source->getProfile(), $target->getProfile());
$relationship['target'] =
- $this->relationshipDetailsArray($target, $source);
+ $this->relationshipDetailsArray($target->getProfile(), $source->getProfile());
return array('relationship' => $relationship);
}
- function relationshipDetailsArray($source, $target)
+ function relationshipDetailsArray(Profile $source, Profile $target)
{
$details = array();
- $source_profile = $source->getProfile();
- $target_profile = $target->getProfile();
-
- $details['screen_name'] = $source->nickname;
- $details['followed_by'] = $target->isSubscribed($source_profile);
- $details['following'] = $source->isSubscribed($target_profile);
+ $details['screen_name'] = $source->getNickname();
+ $details['followed_by'] = $target->isSubscribed($source);
- $notifications = false;
-
- if ($source->isSubscribed($target_profile)) {
- $sub = Subscription::pkeyGet(array('subscriber' =>
- $source->id, 'subscribed' => $target->id));
-
- if (!empty($sub)) {
- $notifications = ($sub->jabber || $sub->sms);
- }
+ try {
+ $sub = Subscription::getSubscription($source, $target);
+ $details['following'] = true;
+ $details['notifications_enabled'] = ($sub->jabber || $sub->sms);
+ } catch (NoResultException $e) {
+ $details['following'] = false;
+ $details['notifications_enabled'] = false;
}
- $details['notifications_enabled'] = $notifications;
- $details['blocking'] = $source->hasBlocked($target_profile);
+ $details['blocking'] = $source->hasBlocked($target);
$details['id'] = intval($source->id);
return $details;
function showSingleAtomStatus($notice)
{
header('Content-Type: application/atom+xml; charset=utf-8');
- print $notice->asAtomEntry(true, true, true, $this->auth_user);
+ print $notice->asAtomEntry(true, true, true, $this->scoped);
}
function show_single_json_status($notice)
return User::getKV('nickname', $nickname);
} else {
// Fall back to trying the currently authenticated user
- return $this->auth_user;
+ return $this->scoped->getUser();
}
} else if (self::is_decimal($id)) {
}
if (!empty($list) && $list->private) {
- if ($this->auth_user->id == $list->tagger) {
+ if ($this->scoped->id == $list->tagger) {
return $list;
}
} else {
'broughtbyurl' => null,
'closed' => false,
'inviteonly' => true,
- 'private' => true,
+ 'private' => false,
'ssl' => 'never',
'sslserver' => null,
'dupelimit' => 60, // default for same person saying the same thing
'newuser' =>
array('default' => null,
'welcome' => null),
+ 'linkify' => array(
+ 'bare_domains' => false, // convert domain.com to <a href="http://domain.com/" ...>domain.com</a> ?
+ ),
'attachments' =>
array('server' => null,
'dir' => INSTALLDIR . '/file/',
'user_quota' => 50000000,
'monthly_quota' => 15000000,
'uploads' => true,
+ 'filename_base' => 'hash', // for new files, choose one: 'upload', 'hash'
'show_html' => false, // show (filtered) text/html attachments (and oEmbed HTML etc.). Doesn't affect AJAX calls.
'show_thumbs' => true, // show thumbnails in notice lists for uploaded images, and photos and videos linked remotely that provide oEmbed info
'process_links' => true, // check linked resources for embeddable photos and videos; this will hit referenced external web sites when processing new messages.
return false;
}
+ public static function getHandlers($name)
+ {
+ return Event::$_handlers[$name];
+ }
+
/**
* Disables any and all handlers that have been set up so far;
* use only if you know it's safe to reinitialize all plugins.
var $width;
var $rotate=0; // degrees to rotate for properly oriented image (extrapolated from EXIF etc.)
var $animated = null; // Animated image? (has more than 1 frame). null means untested
+ var $mimetype = null; // The _ImageFile_ mimetype, _not_ the originating File object
- function __construct($id=null, $filepath=null, $type=null, $width=null, $height=null)
+ function __construct($id, $filepath)
{
$this->id = $id;
$this->filepath = $filepath;
throw new UnsupportedMediaException(_('Unsupported image format.'), $this->filepath);
}
- $this->type = ($info) ? $info[2]:$type;
- $this->width = ($info) ? $info[0]:$width;
- $this->height = ($info) ? $info[1]:$height;
+ $this->width = $info[0];
+ $this->height = $info[1];
+ $this->type = $info[2];
+ $this->mimetype = $info['mime'];
if ($this->type == IMAGETYPE_JPEG && function_exists('exif_read_data')) {
// Orientation value to rotate thumbnails properly
public function getPath()
{
if (!file_exists($this->filepath)) {
- throw new ServerException('No file in ImageFile filepath');
+ throw new FileNotFoundException($this->filepath);
}
return $this->filepath;
$pass = false;
}
- $reqs = array('gd', 'curl', 'json',
+ $reqs = array('gd', 'curl', 'intl', 'json',
'xmlwriter', 'mbstring', 'xml', 'dom', 'simplexml');
foreach ($reqs as $req) {
var $short_fileurl = null;
var $mimetype = null;
- function __construct(Profile $scoped, $filename = null, $mimetype = null)
+ function __construct(Profile $scoped, $filename = null, $mimetype = null, $filehash = null)
{
$this->scoped = $scoped;
$this->filename = $filename;
$this->mimetype = $mimetype;
+ $this->filehash = $filehash;
$this->fileRecord = $this->storeFile();
$this->fileurl = common_local_url('attachment',
protected function storeFile()
{
+ $filepath = File::path($this->filename);
+ if (!empty($this->filename) && $this->filehash === null) {
+ // Calculate if we have an older upload method somewhere (Qvitter) that
+ // doesn't do this before calling new MediaFile on its local files...
+ $this->filehash = hash_file(File::FILEHASH_ALG, $filepath);
+ if ($this->filehash === false) {
+ throw new ServerException('Could not read file for hashing');
+ }
+ }
+
+ try {
+ $file = File::getByHash($this->filehash);
+ // We're done here. Yes. Already. We assume sha256 won't collide on us anytime soon.
+ return $file;
+ } catch (NoResultException $e) {
+ // Well, let's just continue below.
+ }
+
+ $fileurl = File::url($this->filename);
$file = new File;
$file->filename = $this->filename;
- $file->url = File::url($this->filename);
- $filepath = File::path($this->filename);
+ $file->urlhash = File::hashurl($fileurl);
+ $file->url = $fileurl;
+ $file->filehash = $this->filehash;
$file->size = filesize($filepath);
+ if ($file->size === false) {
+ throw new ServerException('Could not read file to get its size');
+ }
$file->date = time();
$file->mimetype = $this->mimetype;
+
$file_id = $file->insert();
if ($file_id===false) {
function maybeAddRedir($file_id, $url)
{
- $file_redir = File_redirection::getKV('url', $url);
-
- if (!$file_redir instanceof File_redirection) {
+ try {
+ $file_redir = File_redirection::getByUrl($url);
+ } catch (NoResultException $e) {
$file_redir = new File_redirection;
+ $file_redir->urlhash = File::hashurl($url);
$file_redir->url = $url;
$file_redir->file_id = $file_id;
throw new ClientException(_('System error uploading file.'));
}
- // Throws exception if additional size does not respect quota
- File::respectsQuota($scoped, $_FILES[$param]['size']);
+ // TODO: Make documentation clearer that this won't work for files >2GiB because
+ // PHP is stupid in its 32bit head. But noone accepts 2GiB files with PHP
+ // anyway... I hope.
+ $filehash = hash_file(File::FILEHASH_ALG, $_FILES[$param]['tmp_name']);
- $mimetype = self::getUploadedMimeType($_FILES[$param]['tmp_name'],
- $_FILES[$param]['name']);
+ try {
+ $file = File::getByHash($filehash);
+ // If no exception is thrown the file exists locally, so we'll use that and just add redirections.
+ $filename = $file->filename;
+ $mimetype = $file->mimetype;
+
+ } catch (NoResultException $e) {
+ // We have to save the upload as a new local file. This is the normal course of action.
- $basename = basename($_FILES[$param]['name']);
- $filename = File::filename($scoped, $basename, $mimetype);
- $filepath = File::path($filename);
+ // Throws exception if additional size does not respect quota
+ // This test is only needed, of course, if we're uploading something new.
+ File::respectsQuota($scoped, $_FILES[$param]['size']);
- $result = move_uploaded_file($_FILES[$param]['tmp_name'], $filepath);
+ $mimetype = self::getUploadedMimeType($_FILES[$param]['tmp_name'], $_FILES[$param]['name']);
- if (!$result) {
- // TRANS: Client exception thrown when a file upload operation fails because the file could
- // TRANS: not be moved from the temporary folder to the permanent file location.
- throw new ClientException(_('File could not be moved to destination directory.'));
+ switch (common_config('attachments', 'filename_base')) {
+ case 'upload':
+ $basename = basename($_FILES[$param]['name']);
+ $filename = File::filename($scoped, $basename, $mimetype);
+ break;
+ case 'hash':
+ default:
+ $filename = strtolower($filehash) . '.' . File::guessMimeExtension($mimetype);
+ }
+ $filepath = File::path($filename);
+
+ $result = move_uploaded_file($_FILES[$param]['tmp_name'], $filepath);
+
+ if (!$result) {
+ // TRANS: Client exception thrown when a file upload operation fails because the file could
+ // TRANS: not be moved from the temporary folder to the permanent file location.
+ throw new ClientException(_('File could not be moved to destination directory.'));
+ }
}
- return new MediaFile($scoped, $filename, $mimetype);
+ return new MediaFile($scoped, $filename, $mimetype, $filehash);
}
static function fromFilehandle($fh, Profile $scoped) {
-
$stream = stream_get_meta_data($fh);
+ // So far we're only handling filehandles originating from tmpfile(),
+ // so we can always do hash_file on $stream['uri'] as far as I can tell!
+ $filehash = hash_file(File::FILEHASH_ALG, $stream['uri']);
- File::respectsQuota($scoped, filesize($stream['uri']));
-
- $mimetype = self::getUploadedMimeType($stream['uri']);
-
- $filename = File::filename($scoped, "email", $mimetype);
-
- $filepath = File::path($filename);
+ try {
+ $file = File::getByHash($filehash);
+ // Already have it, so let's reuse the locally stored File
+ $filename = $file->filename;
+ $mimetype = $file->mimetype;
+ } catch (NoResultException $e) {
+ File::respectsQuota($scoped, filesize($stream['uri']));
+
+ $mimetype = self::getUploadedMimeType($stream['uri']);
+
+ switch (common_config('attachments', 'filename_base')) {
+ case 'upload':
+ $filename = File::filename($scoped, "email", $mimetype);
+ break;
+ case 'hash':
+ default:
+ $filename = strtolower($filehash) . '.' . File::guessMimeExtension($mimetype);
+ }
+ $filepath = File::path($filename);
- $result = copy($stream['uri'], $filepath) && chmod($filepath, 0664);
+ $result = copy($stream['uri'], $filepath) && chmod($filepath, 0664);
- if (!$result) {
- // TRANS: Client exception thrown when a file upload operation fails because the file could
- // TRANS: not be moved from the temporary folder to the permanent file location.
- throw new ClientException(_('File could not be moved to destination directory.' .
- $stream['uri'] . ' ' . $filepath));
+ if (!$result) {
+ // TRANS: Client exception thrown when a file upload operation fails because the file could
+ // TRANS: not be moved from the temporary folder to the permanent file location.
+ throw new ClientException(_('File could not be moved to destination directory.' .
+ $stream['uri'] . ' ' . $filepath));
+ }
}
- return new MediaFile($scoped, $filename, $mimetype);
+ return new MediaFile($scoped, $filename, $mimetype, $filehash);
}
/**
function endCreateTable($name, array $def)
{
$engine = $this->preferredEngine($def);
- return ") ENGINE=$engine CHARACTER SET utf8 COLLATE utf8_bin";
+ return ") ENGINE=$engine CHARACTER SET utf8mb4 COLLATE utf8mb4_bin";
}
function preferredEngine($def)
if (strtolower($oldProps['ENGINE']) != strtolower($engine)) {
$phrase[] = "ENGINE=$engine";
}
- if (strtolower($oldProps['TABLE_COLLATION']) != 'utf8_bin') {
- $phrase[] = 'DEFAULT CHARSET=utf8';
- $phrase[] = 'COLLATE=utf8_bin';
+ if (strtolower($oldProps['TABLE_COLLATION']) != 'utf8mb4_bin') {
+ $phrase[] = 'CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin';
+ $phrase[] = 'DEFAULT CHARACTER SET = utf8mb4';
+ $phrase[] = 'DEFAULT COLLATE = utf8mb4_bin';
}
}
* @link http://status.net/
*/
-if (!defined('STATUSNET')) {
- exit(1);
-}
+if (!defined('GNUSOCIAL')) { exit(1); }
class SchemaUpdater
{
*/
public function register($tableName, array $tableDef)
{
+ // Check if the table we're registering is related to a Managed_DataObject
+ if (is_a(ucfirst($tableName), 'Managed_DataObject', true)) {
+ call_user_func("{$tableName}::beforeSchemaUpdate");
+ }
+
$this->tables[$tableName] = $tableDef;
}
return $email;
}
+function common_purify($html)
+{
+ require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
+
+ $config = array('safe' => 1,
+ 'deny_attribute' => 'id,style,on*');
+
+ $html = common_remove_unicode_formatting($html);
+
+ return htmLawed($html, $config);
+}
+
+function common_remove_unicode_formatting($text)
+{
+ // Strip Unicode text formatting/direction codes
+ // this is pretty dangerous for visualisation of text and can be used for mischief
+ return preg_replace('/[\\x{200b}-\\x{200f}\\x{202a}-\\x{202e}]/u', '', $text);
+}
+
/**
* Partial notice markup rendering step: build links to !group references.
*
*/
function common_render_content($text, Notice $notice)
{
- $r = common_render_text($text);
- $r = common_linkify_mentions($r, $notice);
- return $r;
+ $text = common_render_text($text);
+ $text = common_linkify_mentions($text, $notice);
+ return $text;
}
/**
function common_render_text($text)
{
- $r = nl2br(htmlspecialchars($text));
+ $text = common_remove_unicode_formatting($text);
+ $text = nl2br(htmlspecialchars($text));
- $r = preg_replace('/[\x{0}-\x{8}\x{b}-\x{c}\x{e}-\x{19}]/', '', $r);
- $r = common_replace_urls_callback($r, 'common_linkify');
- $r = preg_replace_callback('/(^|\"\;|\'|\(|\[|\{|\s+)#([\pL\pN_\-\.]{1,64})/u',
- function ($m) { return "{$m[1]}#".common_tag_link($m[2]); }, $r);
+ $text = preg_replace('/[\x{0}-\x{8}\x{b}-\x{c}\x{e}-\x{19}]/', '', $text);
+ $text = common_replace_urls_callback($text, 'common_linkify');
+ $text = preg_replace_callback('/(^|\"\;|\'|\(|\[|\{|\s+)#([\pL\pN_\-\.]{1,64})/u',
+ function ($m) { return "{$m[1]}#".common_tag_link($m[2]); }, $text);
// XXX: machine tags
- return $r;
+ return $text;
}
/**
'|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'. //IPv4
'|(?:'. //IPv6
'\[?(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}(?:(?:[0-9A-Fa-f]{1,4})|:))|(?:(?:[0-9A-Fa-f]{1,4}:){6}(?::|(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})|(?::[0-9A-Fa-f]{1,4})))|(?:(?:[0-9A-Fa-f]{1,4}:){5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){4}(?::[0-9A-Fa-f]{1,4}){0,1}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){3}(?::[0-9A-Fa-f]{1,4}){0,2}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){2}(?::[0-9A-Fa-f]{1,4}){0,3}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:)(?::[0-9A-Fa-f]{1,4}){0,4}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?::(?::[0-9A-Fa-f]{1,4}){0,5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))\]?(?<!:)'.
- ')|(?:'. //DNS
- '(?:[\pN\pL\-\_\+\%\~]+(?:\:[\pN\pL\-\_\+\%\~]+)?\@)?'. //user:pass@
- '[\pN\pL\-\_]+(?:\.[\pN\pL\-\_]+)*\.'.
- //tld list from http://data.iana.org/TLD/tlds-alpha-by-domain.txt, also added local, loc, and onion
- '(?:AC|AD|AE|AERO|AF|AG|AI|AL|AM|AN|AO|AQ|AR|ARPA|AS|ASIA|AT|AU|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BIZ|BJ|BM|BN|BO|BR|BS|BT|BV|BW|BY|BZ|CA|CAT|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|COM|COOP|CR|CU|CV|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EDU|EE|EG|ER|ES|ET|EU|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GOV|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|INFO|INT|IO|IQ|IR|IS|IT|JE|JM|JO|JOBS|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MG|MH|MIL|MK|ML|MM|MN|MO|MOBI|MP|MQ|MR|MS|MT|MU|MUSEUM|MV|MW|MX|MY|MZ|NA|NAME|NC|NE|NET|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|ORG|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PRO|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|ST|SU|SV|SY|SZ|TC|TD|TEL|TF|TG|TH|TJ|TK|TL|TM|TN|TO|TP|TR|TRAVEL|TT|TV|TW|TZ|UA|UG|UK|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|XN--0ZWM56D|测试|XN--11B5BS3A9AJ6G|परीक्षा|XN--80AKHBYKNJ4F|испытание|XN--9T4B11YI5A|테스트|XN--DEBA0AD|טעסט|XN--G6W251D|測試|XN--HGBK6AJ7F53BBA|آزمایشی|XN--HLCJ6AYA9ESC7A|பரிட்சை|XN--JXALPDLP|δοκιμή|XN--KGBECHTV|إختبار|XN--ZCKZAH|テスト|YE|YT|YU|ZA|ZM|ZONE|ZW|local|loc|onion)'.
- ')(?![\pN\pL\-\_])'.
+ ')'.
+ (common_config('linkify', 'bare_domains')
+ ? '|(?:'. //DNS
+ '(?:[\pN\pL\-\_\+\%\~]+(?:\:[\pN\pL\-\_\+\%\~]+)?\@)?'. //user:pass@
+ '[\pN\pL\-\_]+(?:\.[\pN\pL\-\_]+)*\.'.
+ //tld list from http://data.iana.org/TLD/tlds-alpha-by-domain.txt, also added local, loc, and onion
+ '(?:AC|AD|AE|AERO|AF|AG|AI|AL|AM|AN|AO|AQ|AR|ARPA|AS|ASIA|AT|AU|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BIZ|BJ|BM|BN|BO|BR|BS|BT|BV|BW|BY|BZ|CA|CAT|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|COM|COOP|CR|CU|CV|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EDU|EE|EG|ER|ES|ET|EU|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GOV|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|INFO|INT|IO|IQ|IR|IS|IT|JE|JM|JO|JOBS|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MG|MH|MIL|MK|ML|MM|MN|MO|MOBI|MP|MQ|MR|MS|MT|MU|MUSEUM|MV|MW|MX|MY|MZ|NA|NAME|NC|NE|NET|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|ORG|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PRO|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|ST|SU|SV|SY|SZ|TC|TD|TEL|TF|TG|TH|TJ|TK|TL|TM|TN|TO|TP|TR|TRAVEL|TT|TV|TW|TZ|UA|UG|UK|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|XN--0ZWM56D|测试|XN--11B5BS3A9AJ6G|परीक्षा|XN--80AKHBYKNJ4F|испытание|XN--9T4B11YI5A|테스트|XN--DEBA0AD|טעסט|XN--G6W251D|測試|XN--HGBK6AJ7F53BBA|آزمایشی|XN--HLCJ6AYA9ESC7A|பரிட்சை|XN--JXALPDLP|δοκιμή|XN--KGBECHTV|إختبار|XN--ZCKZAH|テスト|YE|YT|YU|ZA|ZM|ZONE|ZW|local|loc|onion)'.
+ ')(?![\pN\pL\-\_])'
+ : '') . // if common_config('linkify', 'bare_domains') is false, don't add anything here
')'.
'(?:'.
'(?:\:\d+)?'. //:port
return preg_replace('/[\p{Cc}\p{Cs}]/u', '*', $str);
}
+function common_slugify($str)
+{
+ $str = transliterator_transliterate(
+ 'Any-Latin;' . // any charset to latin compatible
+ 'NFD;' . // decompose
+ '[:Nonspacing Mark:] Remove;' . // remove nonspacing marks (accents etc.)
+ 'NFC;' . // composite again
+ '[:Punctuation:] Remove;' . // remove punctuation (.,¿? etc.)
+ 'Lower();' . // turn into lowercase
+ 'Latin-ASCII;', // get ASCII equivalents (ð to d for example)
+ $str);
+ return preg_replace('/[^\pL\pN]/', '', $str);
+}
+
function common_tag_link($tag)
{
$canonical = common_canonical_tag($tag);
function common_canonical_tag($tag)
{
- // only alphanum
- $tag = preg_replace('/[^\pL\pN]/u', '', $tag);
- $tag = mb_convert_case($tag, MB_CASE_LOWER, "UTF-8");
- $tag = substr($tag, 0, 64);
- return $tag;
+ $tag = common_slugify($tag);
+ $tag = substr($tag, 0, 64);
+ return $tag;
}
function common_valid_profile_tag($str)
{
static $empty_tag = array('base', 'meta', 'link', 'hr',
'br', 'param', 'img', 'area',
- 'input', 'col');
+ 'input', 'col', 'source');
// XXX: check namespace
if (in_array($tag, $empty_tag)) {
$this->xw->endElement();
// Only attach to traditional-style forms
var textarea = form.find('.notice_data-text:first');
- if (textarea.length == 0) {
+ if (textarea.length === 0) {
return;
}
.appendTo(ul);
};
};
+
+/**
+ * Called when a people tag edit box is shown in the interface
+ *
+ * - loads the jQuery UI autocomplete plugin
+ * - sets event handlers for tag completion
+ *
+ */
+SN.Init.PeopletagAutocomplete = function(txtBox) {
+ var split,
+ extractLast;
+
+ split = function(val) {
+ return val.split( /\s+/ );
+ };
+
+ extractLast = function(term) {
+ return split(term).pop();
+ };
+
+ // don't navigate away from the field on tab when selecting an item
+ txtBox
+ .on('keydown', function(event) {
+ if (event.keyCode === $.ui.keyCode.TAB &&
+ $(this).data('ui-autocomplete').menu.active) {
+ event.preventDefault();
+ }
+ })
+ .autocomplete({
+ minLength: 0,
+ source: function(request, response) {
+ // delegate back to autocomplete, but extract the last term
+ response($.ui.autocomplete.filter(
+ SN.C.PtagACData, extractLast(request.term)));
+ },
+ focus: function () {
+ return false;
+ },
+ select: function(event, ui) {
+ var terms = split(this.value);
+ terms.pop();
+ terms.push(ui.item.value);
+ terms.push('');
+ this.value = terms.join(' ');
+ return false;
+ }
+ })
+ .data('ui-autocomplete')
+ ._renderItem = function (ul, item) {
+ // FIXME: with jQuery UI you cannot have it highlight the match
+ var _l = '<a class="ptag-ac-line-tag">' + item.tag +
+ ' <em class="privacy_mode">' + item.mode + '</em>' +
+ '<span class="freq">' + item.freq + '</span></a>';
+
+ return $('<li/>')
+ .addClass('mode-' + item.mode)
+ .addClass('ptag-ac-line')
+ .data('item.autocomplete', item)
+ .append(_l)
+ .appendTo(ul);
+ };
+};
+
+$(document).on('click', '.peopletags_edit_button', function () {
+ SN.Init.PeopletagAutocomplete($(this).closest('dd').find('[name="tags"]'));
+});
class Homepage_blacklist extends Managed_DataObject
{
public $__table = 'homepage_blacklist'; // table name
- public $pattern; // varchar(255) pattern
+ public $pattern; // varchar(191) pattern not 255 because utf8mb4 takes more space
public $created; // datetime not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
{
return array(
'fields' => array(
- 'pattern' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'blacklist pattern'),
+ 'pattern' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'blacklist pattern'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
class Nickname_blacklist extends Managed_DataObject
{
public $__table = 'nickname_blacklist'; // table name
- public $pattern; // varchar(255) pattern
+ public $pattern; // varchar(191) pattern not 255 because utf8mb4 takes more space
public $created; // datetime not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
{
return array(
'fields' => array(
- 'pattern' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'blacklist pattern'),
+ 'pattern' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'blacklist pattern'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
public $id; // UUID
public $profile_id; // int
- public $title; // varchar(255)
+ public $title; // varchar(191) not 255 because utf8mb4 takes more space
public $summary; // text
public $content; // text
- public $uri; // text
- public $url; // text
+ public $uri; // varchar(191) not 255 because utf8mb4 takes more space
+ public $url; // varchar(191) not 255 because utf8mb4 takes more space
public $created; // datetime
public $modified; // datetime
'not null' => true,
'description' => 'Author profile ID'),
'title' => array('type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'description' => 'title of the entry'),
'summary' => array('type' => 'text',
'description' => 'initial summary'),
'content' => array('type' => 'text',
'description' => 'HTML content of the entry'),
'uri' => array('type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'description' => 'URI (probably http://) for this entry'),
'url' => array('type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'description' => 'URL (probably http://) for this entry'),
'created' => array('type' => 'datetime',
'not null' => true,
$be->id = (string) new UUID();
$be->profile_id = $profile->id;
$be->title = $title; // Note: not HTML-protected
- $be->content = self::purify($content);
+ $be->content = common_purify($content);
if (array_key_exists('summary', $options)) {
- $be->summary = self::purify($options['summary']);
+ $be->summary = common_purify($options['summary']);
} else {
// Already purified
$be->summary = self::summarize($be->content);
return $obj;
}
-
- /**
- * Clean up input HTML
- */
- static function purify($html)
- {
- require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
-
- $config = array('safe' => 1,
- 'deny_attribute' => 'id,style,on*');
- $pure = htmLawed($html, $config);
-
- return $pure;
- }
}
public $__table = 'bookmark'; // table name
public $id; // char(36) primary_key not_null
public $profile_id; // int(4) not_null
- public $url; // varchar(255) not_null
- public $title; // varchar(255)
+ public $url; // varchar(191) not_null not 255 because utf8mb4 takes more space
+ public $title; // varchar(191) not 255 because utf8mb4 takes more space
+ public $uri; // varchar(191) not 255 because utf8mb4 takes more space
public $description; // text
- public $uri; // varchar(255)
public $created; // datetime
public static function schemaDef()
'not null' => true),
'profile_id' => array('type' => 'int', 'not null' => true),
'uri' => array('type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'not null' => true),
'url' => array('type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'not null' => true),
- 'title' => array('type' => 'varchar', 'length' => 255),
+ 'title' => array('type' => 'varchar', 'length' => 191),
'description' => array('type' => 'text'),
'created' => array('type' => 'datetime', 'not null' => true),
),
public $__table = 'message'; // table name
public $id; // int(4) primary_key not_null
- public $uri; // varchar(255) unique_key
+ public $uri; // varchar(191) unique_key not 255 because utf8mb4 takes more space
public $from_profile; // int(4) not_null
public $to_profile; // int(4) not_null
public $content; // text()
public $rendered; // text()
- public $url; // varchar(255)
+ public $url; // varchar(191) not 255 because utf8mb4 takes more space
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
public $source; // varchar(32)
return array(
'fields' => array(
'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'),
- 'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier'),
+ 'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier'),
'from_profile' => array('type' => 'int', 'not null' => true, 'description' => 'who the message is from'),
'to_profile' => array('type' => 'int', 'not null' => true, 'description' => 'who the message is to'),
'content' => array('type' => 'text', 'description' => 'message content'),
'rendered' => array('type' => 'text', 'description' => 'HTML version of the content'),
- 'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL of any attachment (image, video, bookmark, whatever)'),
+ 'url' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL of any attachment (image, video, bookmark, whatever)'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
'source' => array('type' => 'varchar', 'length' => 32, 'description' => 'source of comment, like "web", "im", or "clientname"'),
* @link http://status.net/
*/
-if (!defined('STATUSNET'))
-{
- exit(1);
-}
-
-require_once INSTALLDIR . '/lib/publicgroupnav.php';
+if (!defined('GNUSOCIAL')) { exit(1); }
/**
* Group directory
* @category Directory
* @package StatusNet
* @author Zach Copley <zach@status.net>
+ * @author Mikael Nordfeldth <mmn@hethane.se>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
-class GroupdirectoryAction extends Action
+class GroupdirectoryAction extends ManagedAction
{
/**
* The page we're on
return true;
}
- /**
- * Take arguments for running
- *
- * @param array $args $_REQUEST args
- *
- * @return boolean success flag
- */
- function prepare($args)
+ protected function doPreparation()
{
- parent::prepare($args);
-
$this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1;
$this->filter = $this->arg('filter', 'all');
$this->reverse = $this->boolean('reverse');
$this->sort = $this->arg('sort', 'nickname');
common_set_returnto($this->selfUrl());
-
- return true;
- }
-
- /**
- * Handle request
- *
- * Shows the page
- *
- * @param array $args $_REQUEST args; handled in prepare()
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
- $this->showPage();
}
/**
{
$group = new User_group();
- $offset = ($this->page-1) * PROFILES_PER_PAGE;
- $limit = PROFILES_PER_PAGE + 1;
+ // Disable this to get global group searches
+ $group->joinAdd(array('id', 'local_group:group_id'));
- if (isset($this->q)) {
+ $order = false;
- $order = 'user_group.created ASC';
-
- if ($this->sort == 'nickname') {
- if ($this->reverse) {
- $order = 'user_group.nickname DESC';
- } else {
- $order = 'user_group.nickname ASC';
- }
- } else {
- if ($this->reverse) {
- $order = 'user_group.created DESC';
- }
- }
-
- $sql = <<< GROUP_QUERY_END
-SELECT user_group.*
-FROM user_group
-JOIN local_group ON user_group.id = local_group.group_id
-ORDER BY %s
-LIMIT %d, %d
-GROUP_QUERY_END;
-
- $cnt = 0;
- $group->query(sprintf($sql, $order, $limit, $offset));
- $group->find();
+ if (!empty($this->q)) {
+ $wheres = array('nickname', 'fullname', 'homepage', 'description', 'location');
+ foreach ($wheres as $where) {
+ // Double % because of sprintf
+ $group->whereAdd(sprintf('LOWER(%1$s.%2$s) LIKE LOWER("%%%3$s%%")',
+ $group->escapedTableName(), $where,
+ $group->escape($this->q)),
+ 'OR');
+ }
+ $order = sprintf('%1$s.%2$s %3$s',
+ $group->escapedTableName(),
+ $this->getSortKey('created'),
+ $this->reverse ? 'DESC' : 'ASC');
} else {
// User is browsing via AlphaNav
- $sort = $this->getSortKey();
-
- $sql = <<< GROUP_QUERY_END
-SELECT user_group.*
-FROM user_group
-JOIN local_group ON user_group.id = local_group.group_id
-GROUP_QUERY_END;
- switch($this->filter)
- {
+ switch($this->filter) {
case 'all':
// NOOP
break;
case '0-9':
- $sql .=
- ' AND LEFT(user_group.nickname, 1) BETWEEN \'0\' AND \'9\'';
+ $group->whereAdd(sprintf('LEFT(%1$s.%2$s, 1) BETWEEN %3$s AND %4$s',
+ $group->escapedTableName(),
+ 'nickname',
+ $group->_quote("0"),
+ $group->_quote("9")));
break;
default:
- $sql .= sprintf(
- ' AND LEFT(LOWER(user_group.nickname), 1) = \'%s\'',
- $this->filter
- );
+ $group->whereAdd(sprintf('LEFT(LOWER(%1$s.%2$s), 1) = %3$s',
+ $group->escapedTableName(),
+ 'nickname',
+ $group->_quote($this->filter)));
}
- $sql .= sprintf(
- ' ORDER BY user_group.%s %s, user_group.nickname ASC LIMIT %d, %d',
- $sort,
- $this->reverse ? 'DESC' : 'ASC',
- $offset,
- $limit
- );
-
- $group->query($sql);
+ $order = sprintf('%1$s.%2$s %3$s, %1$s.%4$s ASC',
+ $group->escapedTableName(),
+ $this->getSortKey('nickname'),
+ $this->reverse ? 'DESC' : 'ASC',
+ 'nickname');
}
+ $offset = ($this->page-1) * PROFILES_PER_PAGE;
+ $limit = PROFILES_PER_PAGE + 1;
+
+ $group->orderBy($order);
+ $group->limit($offset, $limit);
+
+ $group->find();
+
return $group;
}
*
* @return string a column name for sorting
*/
- function getSortKey()
+ function getSortKey($def='created')
{
switch ($this->sort) {
case 'nickname':
- return $this->sort;
- break;
case 'created':
return $this->sort;
- break;
default:
- return 'nickname';
+ return $def;
}
}
* @link http://status.net/
*/
-if (!defined('STATUSNET'))
-{
- exit(1);
-}
-
-require_once INSTALLDIR . '/lib/publicgroupnav.php';
+if (!defined('GNUSOCIAL')) { exit(1); }
/**
* User directory
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
-class UserdirectoryAction extends Action
+class UserdirectoryAction extends ManagedAction
{
/**
* The page we're on
return true;
}
- /**
- * Take arguments for running
- *
- * @param array $args $_REQUEST args
- *
- * @return boolean success flag
- */
- function prepare($args)
+ protected function doPreparation()
{
- parent::prepare($args);
-
$this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1;
$this->filter = $this->arg('filter', 'all');
$this->reverse = $this->boolean('reverse');
$this->sort = $this->arg('sort', 'nickname');
common_set_returnto($this->selfUrl());
-
- return true;
- }
-
- /**
- * Handle request
- *
- * Shows the page
- *
- * @param array $args $_REQUEST args; handled in prepare()
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
- $this->showPage();
}
/**
{
$profile = new Profile();
+ // Comment this out or disable to get global profile searches
+ $profile->joinAdd(array('id', 'user:id'));
+
$offset = ($this->page - 1) * PROFILES_PER_PAGE;
$limit = PROFILES_PER_PAGE + 1;
- if (isset($this->q)) {
+ if (!empty($this->q)) {
// User is searching via query
$search_engine = $profile->getSearchEngine('profile');
$profile->find();
} else {
// User is browsing via AlphaNav
- $sort = $this->getSortKey();
- $sql = 'SELECT profile.* FROM profile, user WHERE profile.id = user.id';
- switch($this->filter)
- {
+ switch ($this->filter) {
case 'all':
// NOOP
break;
case '0-9':
- $sql .=
- ' AND LEFT(profile.nickname, 1) BETWEEN \'0\' AND \'9\'';
+ $profile->whereAdd(sprintf('LEFT(%1$s.%2$s, 1) BETWEEN %3$s AND %4$s',
+ $profile->escapedTableName(),
+ 'nickname',
+ $profile->_quote("0"),
+ $profile->_quote("9")));
break;
default:
- $sql .= sprintf(
- ' AND LEFT(LOWER(profile.nickname), 1) = \'%s\'',
- $this->filter
- );
+ $profile->whereAdd(sprintf('LEFT(LOWER(%1$s.%2$s), 1) = %3$s',
+ $profile->escapedTableName(),
+ 'nickname',
+ $profile->_quote($this->filter)));
}
- $sql .= sprintf(
- ' ORDER BY profile.%s %s, profile.nickname ASC LIMIT %d, %d',
- $sort,
- $this->reverse ? 'DESC' : 'ASC',
- $offset,
- $limit
- );
+ $order = sprintf('%1$s.%2$s %3$s, %1$s.%4$s ASC',
+ $profile->escapedTableName(),
+ $this->getSortKey('nickname'),
+ $this->reverse ? 'DESC' : 'ASC',
+ 'nickname');
+ $profile->orderBy($order);
+ $profile->limit($offset, $limit);
- $profile->query($sql);
+ $profile->find();
}
return $profile;
*
* @return string a column name for sorting
*/
- function getSortKey()
+ function getSortKey($def='nickname')
{
switch ($this->sort) {
case 'nickname':
- return $this->sort;
- break;
case 'created':
return $this->sort;
- break;
default:
return 'nickname';
}
{
public $__table = 'email_reminder';
- public $type; // type of reminder
- public $code; // confirmation code
+ public $type; // type of reminder varchar(191) not 255 because utf8mb4 takes more space
+ public $code; // confirmation code varchar(191) not 255 because utf8mb4 takes more space
public $days; // number of days after code was created
public $sent; // timestamp
public $created; // timestamp
'fields' => array(
'type' => array(
'type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'not null' => true,
'description' => 'type of reminder'
),
'code' => array(
'type' => 'varchar',
'not null' => 'true',
- 'length' => 255,
+ 'length' => 191,
'description' => 'confirmation code'
),
'days' => array(
public $__table = 'happening'; // table name
public $id; // varchar(36) UUID
- public $uri; // varchar(255)
+ public $uri; // varchar(191) not 255 because utf8mb4 takes more space
public $profile_id; // int
public $start_time; // datetime
public $end_time; // datetime
- public $title; // varchar(255)
- public $location; // varchar(255)
- public $url; // varchar(255)
+ public $title; // varchar(191) not 255 because utf8mb4 takes more space
+ public $location; // varchar(191) not 255 because utf8mb4 takes more space
+ public $url; // varchar(191) not 255 because utf8mb4 takes more space
public $description; // text
public $created; // datetime
'not null' => true,
'description' => 'UUID'),
'uri' => array('type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'not null' => true),
'profile_id' => array('type' => 'int', 'not null' => true),
'start_time' => array('type' => 'datetime', 'not null' => true),
'end_time' => array('type' => 'datetime', 'not null' => true),
'title' => array('type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'not null' => true),
'location' => array('type' => 'varchar',
- 'length' => 255),
+ 'length' => 191),
'url' => array('type' => 'varchar',
- 'length' => 255),
+ 'length' => 191),
'description' => array('type' => 'text'),
'created' => array('type' => 'datetime',
'not null' => true),
public $__table = 'rsvp'; // table name
public $id; // varchar(36) UUID
- public $uri; // varchar(255)
+ public $uri; // varchar(191) not 255 because utf8mb4 takes more space
public $profile_id; // int
public $event_id; // varchar(36) UUID
public $response; // tinyint
'not null' => true,
'description' => 'UUID'),
'uri' => array('type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'not null' => true),
'profile_id' => array('type' => 'int'),
'event_id' => array('type' => 'char',
{
public $__table = 'notice_to_item'; // table name
public $notice_id; // int(4) primary_key not_null
- public $item_id; // varchar(255) not null
+ public $item_id; // varchar(191) not null not 255 because utf8mb4 takes more space
public $created; // datetime
/**
{
return array(
new ColumnDef('notice_id', 'integer', null, false, 'PRI'),
- new ColumnDef('item_id', 'varchar', 255, false, 'UNI'),
+ new ColumnDef('item_id', 'varchar', 191, false, 'UNI'),
new ColumnDef('created', 'datetime', null, false)
);
}
public $__table = 'fave'; // table name
public $notice_id; // int(4) primary_key not_null
public $user_id; // int(4) primary_key not_null
- public $uri; // varchar(255)
+ public $uri; // varchar(191) not 255 because utf8mb4 takes more space not 255 because utf8mb4 takes more space
public $created; // datetime multiple_key not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
'fields' => array(
'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice that is the favorite'),
'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user who likes this notice'),
- 'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier, usually a tag URI'),
+ 'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'universally unique identifier, usually a tag URI'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
public $__table = 'photo'; // table name
public $id; // char (36) // UUID
- public $uri; // varchar (255) // This is the corresponding notice's uri.
- public $photo_uri; // varchar (255)
- public $thumb_uri; // varchar (255)
- public $title; // varchar (255)
+ public $uri; // varchar (191) // This is the corresponding notice's uri. not 255 because utf8mb4 takes more space
+ public $photo_uri; // varchar (191) not 255 because utf8mb4 takes more space
+ public $thumb_uri; // varchar (191) not 255 because utf8mb4 takes more space
+ public $title; // varchar (191) not 255 because utf8mb4 takes more space
public $description; // text
public $profile_id; // int
'not null' => true,
'description' => 'UUID'),
'uri' => array('type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'not null' => true),
'photo_uri' => array('type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'not null' => true),
'photo_uri' => array('type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'not null' => true),
'profile_id' => array('type' => 'int', 'not null' => true),
),
public $id; // int(11)
public $notice_id; // int(11)
public $album_id; // int(11)
- public $uri; // varchar(255)
- public $thumb_uri; // varchar(255)
- public $title; // varchar(255)
+ public $uri; // varchar(191) not 255 because utf8mb4 takes more space
+ public $thumb_uri; // varchar(191) not 255 because utf8mb4 takes more space
+ public $title; // varchar(191) not 255 because utf8mb4 takes more space
public $photo_description; // text
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
'id' => array('type' => 'serial', 'not null' => true, 'description' => 'Unique ID for Photo'),
'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'Notice ID for the related notice'),
'album_id' => array('type' => 'int', 'not null' => true, 'description' => 'The parent album ID'),
- 'uri' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'unique address for this photo'),
- 'thumb_uri' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'unique address for this photo thumbnail'),
- 'title' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'The Photo title'),
+ 'uri' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'unique address for this photo'),
+ 'thumb_uri' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'unique address for this photo thumbnail'),
+ 'title' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'The Photo title'),
'photo_description' => array('type' => 'text', 'not null' => true, 'description' => 'A description for this photo'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
public $__table = 'GNUsocialPhotoAlbum';
public $album_id; // int(11) -- Unique identifier for the album
public $profile_id; // int(11) -- Profile ID for the owner of the album
- public $album_name; // varchar(255) -- Title for this album
+ public $album_name; // varchar(191) -- Title for this album not 255 because utf8mb4 takes more space
public $album_description; // text -- A description of the album
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
'fields' => array(
'album_id' => array('type' => 'serial', 'not null' => true, 'description' => 'Unique identifier for the album'),
'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'Profile ID for the owner of the album'),
- 'album_name' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'Title for this album'),
+ 'album_name' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'Title for this album'),
'album_description' => array('type' => 'text', 'not null' => true, 'description' => 'A description for this album'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
public $__table = 'gnusocialprofileextensionfield';
public $id; // int(11)
public $systemname; // varchar(64)
- public $title; // varchar(255)
+ public $title; // varchar(191) not 255 because utf8mb4 takes more space
public $description; // text
- public $type; // varchar(255)
+ public $type; // varchar(191) not 255 because utf8mb4 takes more space
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
'fields' => array(
'id' => array('type' => 'serial', 'not null' => true, 'description' => 'Unique ID for extension field'),
'systemname' => array('type' => 'varchar', 'not null' => true, 'length' => 64, 'description' => 'field systemname'),
- 'title' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'field title'),
+ 'title' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'field title'),
'description' => array('type' => 'text', 'not null' => true, 'description' => 'field description'),
- 'type' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'field type'),
+ 'type' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'field type'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
public $__table = 'video'; // table name
public $id; // char (36) // UUID
- public $uri; // varchar (255) // This is the corresponding notice's uri.
- public $url; // varchar (255)
+ public $uri; // varchar (191) This is the corresponding notice's uri. not 255 because utf8mb4 takes more space
+ public $url; // varchar (191) not 255 because utf8mb4 takes more space
public $profile_id; // int
public static function getByNotice($notice)
'not null' => true,
'description' => 'UUID'),
'uri' => array('type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'not null' => true),
'url' => array('type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'not null' => true),
'profile_id' => array('type' => 'int', 'not null' => true),
),
{
public $__table = 'group_message'; // table name
public $id; // char(36) primary_key not_null
- public $uri; // varchar(255)
+ public $uri; // varchar(191) not 255 because utf8mb4 takes more space
public $from_profile; // int
public $to_group; // int
public $content;
public $rendered;
- public $url;
+ public $url; // varchar(191) not 255 because utf8mb4 takes more space
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
return array(
'fields' => array(
'id' => array('type' => 'char', 'not null' => true, 'length' => 36, 'description' => 'message uuid'),
- 'uri' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'message uri'),
- 'url' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'representation url'),
+ 'uri' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'message uri'),
+ 'url' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'representation url'),
'from_profile' => array('type' => 'int', 'not null' => true, 'description' => 'sending profile ID'),
'to_group' => array('type' => 'int', 'not null' => true, 'description' => 'receiving group ID'),
'content' => array('type' => 'text', 'not null' => true, 'description' => 'message content'),
*/
class Notice_title extends Managed_DataObject
{
- const MAXCHARS = 255;
+ const MAXCHARS = 191; // not 255 because utf8mb4 takes more space
public $__table = 'notice_title'; // table name
public $notice_id; // int(11) primary_key not_null
- public $title; // varchar(255)
+ public $title; // varchar(191) not 255 because utf8mb4 takes more space
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
public $__table = 'feedsub';
public $id;
- public $uri;
+ public $uri; // varchar(191) not 255 because utf8mb4 takes more space
// PuSH subscription data
public $huburi;
return array(
'fields' => array(
'id' => array('type' => 'serial', 'not null' => true, 'description' => 'FeedSub local unique id'),
- 'uri' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'FeedSub uri'),
+ 'uri' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'FeedSub uri'),
'huburi' => array('type' => 'text', 'description' => 'FeedSub hub-uri'),
'secret' => array('type' => 'text', 'description' => 'FeedSub stored secret'),
'sub_state' => array('type' => 'enum("subscribe","active","unsubscribe","inactive","nohub")', 'not null' => true, 'description' => 'subscription state'),
public $__table = 'hubsub';
public $hashkey; // sha1(topic . '|' . $callback); (topic, callback) key is too long for myisam in utf8
- public $topic;
- public $callback;
+ public $topic; // varchar(191) not 255 because utf8mb4 takes more space
+ public $callback; // varchar(191) not 255 because utf8mb4 takes more space
public $secret;
public $lease;
public $sub_start;
return array(
'fields' => array(
'hashkey' => array('type' => 'char', 'not null' => true, 'length' => 40, 'description' => 'HubSub hashkey'),
- 'topic' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'HubSub topic'),
- 'callback' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'HubSub callback'),
+ 'topic' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'HubSub topic'),
+ 'callback' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'HubSub callback'),
'secret' => array('type' => 'text', 'description' => 'HubSub stored secret'),
'lease' => array('type' => 'int', 'description' => 'HubSub leasetime'),
'sub_start' => array('type' => 'datetime', 'description' => 'subscription start'),
{
return array(
'fields' => array(
- 'uri' => array('type' => 'varchar', 'length' => 255, 'not null' => true),
+ 'uri' => array('type' => 'varchar', 'length' => 191, 'not null' => true),
'profile_id' => array('type' => 'integer'),
'group_id' => array('type' => 'integer'),
'peopletag_id' => array('type' => 'integer'),
- 'feeduri' => array('type' => 'varchar', 'length' => 255),
- 'salmonuri' => array('type' => 'varchar', 'length' => 255),
+ 'feeduri' => array('type' => 'varchar', 'length' => 191),
+ 'salmonuri' => array('type' => 'varchar', 'length' => 191),
'avatar' => array('type' => 'text'),
'created' => array('type' => 'datetime', 'not null' => true),
'modified' => array('type' => 'datetime', 'not null' => true),
// Get (safe!) HTML and text versions of the content
- $rendered = $this->purify($sourceContent);
+ $rendered = common_purify($sourceContent);
$content = common_strip_html($rendered);
$shortened = common_shorten_links($content);
// Get (safe!) HTML and text versions of the content
- $rendered = $this->purify($sourceContent);
+ $rendered = common_purify($sourceContent);
$content = common_strip_html($rendered);
$shortened = common_shorten_links($content);
return $saved;
}
- /**
- * Clean up HTML
- */
- protected function purify($html)
- {
- require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
- $config = array('safe' => 1,
- 'deny_attribute' => 'id,style,on*');
- return htmLawed($html, $config);
- }
-
/**
* Filters a list of recipient ID URIs to just those for local delivery.
* @param Profile local profile of sender
*/
public static function ensureFeedURL($feed_url, array $hints=array())
{
+ $oprofile = Ostatus_profile::getKV('feeduri', $feed_url);
+ if ($oprofile instanceof Ostatus_profile) {
+ return $oprofile;
+ }
+
$discover = new FeedDiscovery();
$feeduri = $discover->discoverFromFeedURL($feed_url);
}
if (!empty($location)) {
- if (mb_strlen($location) > 255) {
- $location = mb_substr($note, 0, 255 - 3) . ' … ';
+ if (mb_strlen($location) > 191) { // not 255 because utf8mb4 takes more space
+ $location = mb_substr($note, 0, 191 - 3) . ' … ';
}
}
'text/html');
$filepath = File::path($filename);
+ $fileurl = File::url($filename);
file_put_contents($filepath, $final);
$file = new File;
$file->filename = $filename;
- $file->url = File::url($filename);
+ $file->urlhash = File::hashurl($fileurl);
+ $file->url = $fileurl;
$file->size = filesize($filepath);
$file->date = time();
$file->mimetype = 'text/html';
return array(
'fields' => array(
'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'Notice ID relation'),
- 'profile_uri' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'Profile URI'),
+ 'profile_uri' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'Profile URI'),
'method' => array('type' => 'enum("push","salmon")', 'not null' => true, 'description' => 'source method'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
// Step 4: Is the newly introduced https://example.com/user/1 URI in the list of aliases
// presented by http://example.com/user/1 (i.e. do they both say they are the same identity?)
if (in_array($e->object_uri, $doublecheck_aliases)) {
- common_debug('These identities both say they are each other: "'.$aliased_uri.'" and "'.$e->object_uri);
+ common_debug('URIFIX These identities both say they are each other: "'.$aliased_uri.'" and "'.$e->object_uri.'"');
+ $orig = clone($oprofile);
+ $oprofile->uri = $e->object_uri;
+ common_debug('URIFIX Updating Ostatus_profile URI for '.$aliased_uri.' to '.$oprofile->uri);
+ $oprofile->updateWithKeys($orig, 'uri'); // 'uri' is the primary key column
+ unset($orig);
$this->oprofile = $oprofile;
break; // don't iterate through aliases anymore
}
public $type; // varchar(20)
public $mimetype; // varchar(50)
public $provider; // varchar(50)
- public $provider_url; // varchar(255)
+ public $provider_url; // varchar(191) not 255 because utf8mb4 takes more space
public $width; // int(4)
public $height; // int(4)
public $html; // text()
- public $title; // varchar(255)
+ public $title; // varchar(191) not 255 because utf8mb4 takes more space
public $author_name; // varchar(50)
- public $author_url; // varchar(255)
- public $url; // varchar(255)
+ public $author_url; // varchar(191) not 255 because utf8mb4 takes more space
+ public $url; // varchar(191) not 255 because utf8mb4 takes more space
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
public static function schemaDef()
'type' => array('type' => 'varchar', 'length' => 20, 'description' => 'oEmbed type: photo, video, link, rich'),
'mimetype' => array('type' => 'varchar', 'length' => 50, 'description' => 'mime type of resource'),
'provider' => array('type' => 'varchar', 'length' => 50, 'description' => 'name of this oEmbed provider'),
- 'provider_url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL of this oEmbed provider'),
+ 'provider_url' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL of this oEmbed provider'),
'width' => array('type' => 'int', 'description' => 'width of oEmbed resource when available'),
'height' => array('type' => 'int', 'description' => 'height of oEmbed resource when available'),
'html' => array('type' => 'text', 'description' => 'html representation of this oEmbed resource when applicable'),
- 'title' => array('type' => 'varchar', 'length' => 255, 'description' => 'title of oEmbed resource when available'),
+ 'title' => array('type' => 'varchar', 'length' => 191, 'description' => 'title of oEmbed resource when available'),
'author_name' => array('type' => 'varchar', 'length' => 50, 'description' => 'author name for this oEmbed resource'),
- 'author_url' => array('type' => 'varchar', 'length' => 255, 'description' => 'author URL for this oEmbed resource'),
- 'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL for this oEmbed resource when applicable (photo, link)'),
+ 'author_url' => array('type' => 'varchar', 'length' => 191, 'description' => 'author URL for this oEmbed resource'),
+ 'url' => array('type' => 'varchar', 'length' => 191, 'description' => 'URL for this oEmbed resource when applicable (photo, link)'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
),
'primary key' => array('file_id'),
array(
'fields' => array(
'server_url' => array('type' => 'blob', 'not null' => true),
- 'handle' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'default' => ''), // character set latin1,
+ 'handle' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'default' => ''), // character set latin1,
'secret' => array('type' => 'blob'),
'issued' => array('type' => 'int'),
'lifetime' => array('type' => 'int'),
'assoc_type' => array('type' => 'varchar', 'length' => 64),
),
- 'primary key' => array(array('server_url', 255), 'handle'),
+ 'primary key' => array(array('server_url', 191), 'handle'),
));
$schema->ensureTable('oid_nonces',
array(
'salt' => array('type' => 'char', 'length' => 40),
),
'unique keys' => array(
- 'oid_nonces_server_url_timestamp_salt_key' => array(array('server_url', 255), 'timestamp', 'salt'),
+ 'oid_nonces_server_url_timestamp_salt_key' => array(array('server_url', 191), 'timestamp', 'salt'),
),
));
/* the code below is auto generated do not remove the above tag */
public $__table = 'user_openid'; // table name
- public $canonical; // varchar(255) primary_key not_null
- public $display; // varchar(255) unique_key not_null
+ public $canonical; // varchar(191) primary_key not_null
+ public $display; // varchar(191) unique_key not_null
public $user_id; // int(4) not_null
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
{
return array(
'fields' => array(
- 'canonical' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'OpenID canonical string'),
- 'display' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'OpenID display string'),
+ 'canonical' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'OpenID canonical string'),
+ 'display' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'OpenID display string'),
'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'User ID for OpenID owner'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
/* the code below is auto generated do not remove the above tag */
public $__table = 'user_openid_trustroot'; // table name
- public $trustroot; // varchar(255) primary_key not_null
+ public $trustroot; // varchar(191) primary_key not_null not 255 because utf8mb4 takes more space
public $user_id; // int(4) primary_key not_null
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
{
return array(
'fields' => array(
- 'trustroot' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'OpenID trustroot string'),
+ 'trustroot' => array('type' => 'varchar', 'not null' => true, 'length' => 191, 'description' => 'OpenID trustroot string'),
'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'User ID for OpenID trustroot owner'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
{
public $__table = 'poll'; // table name
public $id; // char(36) primary key not null -> UUID
- public $uri;
+ public $uri; // varchar(191) not 255 because utf8mb4 takes more space
public $profile_id; // int -> profile.id
public $question; // text
public $options; // text; newline(?)-delimited
'description' => 'Per-notice poll data for Poll plugin',
'fields' => array(
'id' => array('type' => 'char', 'length' => 36, 'not null' => true, 'description' => 'UUID'),
- 'uri' => array('type' => 'varchar', 'length' => 255, 'not null' => true),
+ 'uri' => array('type' => 'varchar', 'length' => 191, 'not null' => true),
'profile_id' => array('type' => 'int'),
'question' => array('type' => 'text'),
'options' => array('type' => 'text'),
{
public $__table = 'poll_response'; // table name
public $id; // char(36) primary key not null -> UUID
- public $uri; // varchar(255)
+ public $uri; // varchar(191) not 255 because utf8mb4 takes more space
public $poll_id; // char(36) -> poll.id UUID
public $profile_id; // int -> profile.id
public $selection; // int -> choice #
'description' => 'Record of responses to polls',
'fields' => array(
'id' => array('type' => 'char', 'length' => 36, 'not null' => true, 'description' => 'UUID of the response'),
- 'uri' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'UUID to the response notice'),
+ 'uri' => array('type' => 'varchar', 'length' => 191, 'not null' => true, 'description' => 'UUID to the response notice'),
'poll_id' => array('type' => 'char', 'length' => 36, 'not null' => true, 'description' => 'UUID of poll being responded to'),
'profile_id' => array('type' => 'int'),
'selection' => array('type' => 'int'),
public $__table = 'qna_answer'; // table name
public $id; // char(36) primary key not null -> UUID
- public $uri; // varchar(255)
+ public $uri; // varchar(191) not 255 because utf8mb4 takes more space
public $question_id; // char(36) -> question.id UUID
public $profile_id; // int -> question.id
public $best; // (boolean) int -> whether the question asker has marked this as the best answer
),
'uri' => array(
'type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'not null' => true,
'description' => 'UUID to the answer notice',
),
public $__table = 'qna_question'; // table name
public $id; // char(36) primary key not null -> UUID
- public $uri;
+ public $uri; // varchar(191) not 255 because utf8mb4 takes more space
public $profile_id; // int -> profile.id
public $title; // text
public $description; // text
),
'uri' => array(
'type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'not null' => true
),
'profile_id' => array('type' => 'int'),
array(
'fields' => array(
'subscribed' => array('type' => 'int', 'not null' => true),
- 'url' => array('type' => 'varchar', 'length' => '255', 'not null' => true),
+ 'url' => array('type' => 'varchar', 'length' => '191', 'not null' => true),
'failures' => array('type' => 'int', 'not null' => true, 'default' => 0),
'created' => array('type' => 'datetime', 'not null' => true),
'modified' => array('type' => 'timestamp', 'not null' => true),
public $__table = 'realtime_channel'; // table name
public $user_id; // int -> user.id, can be null
- public $action; // string
- public $arg1; // argument
- public $arg2; // argument, usually null
+ public $action; // varchar(191) not 255 because utf8mb4 takes more space
+ public $arg1; // varchar(191) argument not 255 because utf8mb4 takes more space
+ public $arg2; // varchar(191) usually null not 255 because utf8mb4 takes more space
public $channel_key; // 128-bit shared secret key
public $audience; // listener count
public $created; // created date
'not null' => false,
'description' => 'user viewing page; can be null'),
'action' => array('type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'not null' => true,
'description' => 'page being viewed'),
'arg1' => array('type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'not null' => false,
'description' => 'page argument, like username or tag'),
'arg2' => array('type' => 'varchar',
- 'length' => 255,
+ 'length' => 191,
'not null' => false,
'description' => 'second page argument, like tag for showstream'),
'channel_key' => array('type' => 'varchar',
{
public $__table = 'twitter_synch_status'; // table name
public $foreign_id; // bigint primary_key not_null
- public $timeline; // varchar(255) primary_key not_null
+ public $timeline; // varchar(191) primary_key not_null not 255 because utf8mb4 takes more space
public $last_id; // bigint not_null
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
return array(
'fields' => array(
'foreign_id' => array('type' => 'int', 'size' => 'big', 'not null' => true, 'description' => 'Foreign message ID'),
- 'timeline' => array('type' => 'varchar', 'length' => 255, 'description' => 'timeline name'),
+ 'timeline' => array('type' => 'varchar', 'length' => 191, 'description' => 'timeline name'),
'last_id' => array('type' => 'int', 'size' => 'big', 'not null' => true, 'description' => 'last id fetched'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
/**
* GNU social - a federating social network
*
- * Plugin to make thumbnails of video files with ffmpeg
+ * Plugin to make thumbnails of video files with avconv
*
* PHP version 5
*
/*
* Dependencies:
- * php5-ffmpeg
+ * avconv (external program call)
* php5-gd
*
- * Video support will depend on your ffmpeg.
+ * Todo:
+ * Make sure we support ffmpeg too, so we're not super Debian oriented.
+ *
+ * Video support will depend on your avconv.
*/
class VideoThumbnailsPlugin extends Plugin
{
// The calling function might accidentally pass application/ogg videos.
// If that's a problem, let's fix it in the calling function.
- if ($media !== 'video') {
+ if ($media !== 'video' || empty($file->filename)) {
return true;
}
- $movie = new ffmpeg_movie($file->getPath(), false);
+ // Let's save our frame to a temporary file. If we fail, remove it.
+ $imgPath = tempnam(sys_get_temp_dir(), 'socialthumb-');
- $frames = $movie->getFrameCount();
- if ($frames > 0) {
- $frame = $movie->getFrame(floor($frames/2));
- } else {
- $frame = $movie->getNextKeyFrame();
- }
+ $result = exec('avconv -i '.escapeshellarg($file->getPath()).' -vcodec mjpeg -vframes 1 -f image2 -an '.escapeshellarg($imgPath));
- // We failed to get a frame.
- if (!$frame instanceof ffmpeg_frame) {
- return true;
- }
-
- // Let's save our frame to a temporary file. If we fail, remove it.
- $imgPath = tempnam(sys_get_temp_dir(), 'socialthumb');
- if (!imagejpeg($frame->toGDImage(), $imgPath)) {
+ if (!getimagesize($imgPath)) {
+ common_debug('exec of "avconv" produced a bad/nonexisting image it seems');
@unlink($imgPath);
return true;
}
--- /dev/null
+#!/usr/bin/env php
+<?php
+/*
+ * StatusNet - a distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+
+$shortoptions = 'y';
+$longoptions = array('yes');
+
+$helptext = <<<END_OF_HELP
+clean_file_table.php [options]
+Deletes all local files where the filename cannot be found in the filesystem.
+
+ -y --yes do not wait for confirmation
+
+Will print '.' for each file, except for deleted ones which are marked as 'x'.
+
+END_OF_HELP;
+
+require_once INSTALLDIR.'/scripts/commandline.inc';
+
+if (!have_option('y', 'yes')) {
+ print "About to delete local file entries where the file cannot be found. Are you sure? [y/N] ";
+ $response = fgets(STDIN);
+ if (strtolower(trim($response)) != 'y') {
+ print "Aborting.\n";
+ exit(0);
+ }
+}
+
+print "Deleting";
+$file = new File();
+$file->whereAdd('filename IS NOT NULL'); // local files
+$file->whereAdd('filehash IS NULL', 'AND'); // without filehash value
+if ($file->find()) {
+ while ($file->fetch()) {
+ try {
+ $file->getPath();
+ print '.';
+ } catch (FileNotFoundException $e) {
+ $file->delete();
+ print 'x';
+ }
+ }
+}
+print "\nDONE.\n";
--- /dev/null
+#!/usr/bin/env php
+<?php
+/*
+ * StatusNet - a distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+
+$shortoptions = 'y';
+$longoptions = array('yes');
+
+$helptext = <<<END_OF_HELP
+clean_profiles.php [options]
+Deletes all profile table entries where the profile does not occur in the
+notice table, is not a group and is not a local user. Very MySQL specific I think.
+
+WARNING: This has not been tested thoroughly. Maybe we've missed a table to compare somewhere.
+
+ -y --yes do not wait for confirmation
+
+END_OF_HELP;
+
+require_once INSTALLDIR.'/scripts/commandline.inc';
+
+if (!have_option('y', 'yes')) {
+ print "About to delete profiles that we think are useless to save. Are you sure? [y/N] ";
+ $response = fgets(STDIN);
+ if (strtolower(trim($response)) != 'y') {
+ print "Aborting.\n";
+ exit(0);
+ }
+}
+
+print "Deleting";
+$profile = new Profile();
+$profile->query('SELECT * FROM profile WHERE ' .
+ 'NOT (SELECT COUNT(*) FROM notice WHERE profile_id=profile.id) ' .
+ 'AND NOT (SELECT COUNT(*) FROM user WHERE user.id=profile.id) ' .
+ 'AND NOT (SELECT COUNT(*) FROM user_group WHERE user_group.profile_id=profile.id) ' .
+ 'AND NOT (SELECT COUNT(*) FROM subscription WHERE subscriber=profile.id OR subscribed=profile.id) ');
+while ($profile->fetch()) {
+ echo ' '.$profile->getID().':'.$profile->getNickname();
+ $profile->delete();
+}
+print "\nDONE.\n";
fixupFileGeometry();
deleteLocalFileThumbnailsWithoutFilename();
deleteMissingLocalFileThumbnails();
+ setFilehashOnLocalFiles();
initGroupProfileId();
initLocalGroup();
// Checking if there were any File_thumbnail entries without filename
if ($thumbs->find()) {
while ($thumbs->fetch()) {
- if (!file_exists(File_thumbnail::path($thumbs->filename))) {
+ try {
+ $thumbs->getPath();
+ } catch (FileNotFoundException $e) {
$thumbs->delete();
}
}
printfnq("DONE.\n");
}
+/*
+ * Files are now stored with their hash, so let's generate for previously uploaded files.
+ */
+function setFilehashOnLocalFiles()
+{
+ printfnq('Ensuring all local files have the filehash field set...');
+
+ $file = new File();
+ $file->whereAdd('filename IS NOT NULL'); // local files
+ $file->whereAdd('filehash IS NULL', 'AND'); // without filehash value
+
+ if ($file->find()) {
+ while ($file->fetch()) {
+ try {
+ $orig = clone($file);
+ $file->filehash = hash_file(File::FILEHASH_ALG, $file->getPath());
+ $file->update($orig);
+ } catch (FileNotFoundException $e) {
+ echo "\n WARNING: file ID {$file->id} does not exist on path '{$e->path}'. Clean up the file table?";
+ }
+ }
+ }
+
+ printfnq("DONE.\n");
+}
+
main();
overflow-y: auto;
}
+.notice .e-content img {
+ max-width: 100%;
+}
+
.notice-options {
margin-bottom: 7px;
margin-top: 12px;