Deleted_notice.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. <?php
  2. /*
  3. * Laconica - a distributed open-source microblogging tool
  4. * Copyright (C) 2008, 2009, Control Yourself, Inc.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. if (!defined('GNUSOCIAL')) { exit(1); }
  20. /**
  21. * Table Definition for deleted_notice
  22. */
  23. class Deleted_notice extends Managed_DataObject
  24. {
  25. public $__table = 'deleted_notice'; // table name
  26. public $id; // int(4) primary_key not_null
  27. public $profile_id; // int(4) not_null
  28. public $uri; // varchar(191) unique_key not 255 because utf8mb4 takes more space
  29. public $act_created; // datetime() not_null
  30. public $created; // datetime() not_null
  31. public static function schemaDef()
  32. {
  33. return array(
  34. 'fields' => array(
  35. 'id' => array('type' => 'int', 'not null' => true, 'description' => 'notice ID'),
  36. 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'profile that deleted the notice'),
  37. 'uri' => array('type' => 'varchar', 'length' => 191, 'description' => 'URI of the deleted notice'),
  38. 'act_created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date the notice record was created'),
  39. 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date the notice record was deleted'),
  40. ),
  41. 'primary key' => array('id'),
  42. 'unique keys' => array(
  43. 'deleted_notice_uri_key' => array('uri'),
  44. ),
  45. 'indexes' => array(
  46. 'deleted_notice_profile_id_idx' => array('profile_id'),
  47. ),
  48. );
  49. }
  50. public static function addNew(Notice $notice, Profile $actor=null)
  51. {
  52. if (is_null($actor)) {
  53. $actor = $notice->getProfile();
  54. }
  55. if ($notice->getProfile()->hasRole(Profile_role::DELETED)) {
  56. // Don't emit notices if the notice author is (being) deleted
  57. return false;
  58. }
  59. $act = new Activity();
  60. $act->verb = ActivityVerb::DELETE;
  61. $act->time = time();
  62. $act->id = $notice->getUri();
  63. $act->content = sprintf(_m('<a href="%1$s">%2$s</a> deleted notice <a href="%3$s">{{%4$s}}</a>.'),
  64. htmlspecialchars($actor->getUrl()),
  65. htmlspecialchars($actor->getBestName()),
  66. htmlspecialchars($notice->getUrl()),
  67. htmlspecialchars($notice->getUri())
  68. );
  69. $act->actor = $actor->asActivityObject();
  70. $act->target = new ActivityObject(); // We don't save the notice object, as it's supposed to be removed!
  71. $act->target->id = $notice->getUri();
  72. try {
  73. $act->target->type = $notice->getObjectType();
  74. } catch (NoObjectTypeException $e) {
  75. // This could be for example an RSVP which is a verb and carries no object-type
  76. $act->target->type = null;
  77. }
  78. $act->objects = array(clone($act->target));
  79. $url = $notice->getUrl();
  80. $act->selfLink = $url;
  81. $act->editLink = $url;
  82. // This will make ActivityModeration run saveObjectFromActivity which adds
  83. // a new Deleted_notice entry in the database as well as deletes the notice
  84. // if the actor has permission to do so.
  85. $stored = Notice::saveActivity($act, $actor);
  86. return $stored;
  87. }
  88. static public function fromStored(Notice $stored)
  89. {
  90. $class = get_called_class();
  91. return self::getByKeys( ['uri' => $stored->getUri()] );
  92. }
  93. // The one who deleted the notice, not the notice's author
  94. public function getActor()
  95. {
  96. return Profile::getByID($this->profile_id);
  97. }
  98. // As above: The one who deleted the notice, not the notice's author
  99. public function getActorObject()
  100. {
  101. return $this->getActor()->asActivityObject();
  102. }
  103. static public function getObjectType()
  104. {
  105. return 'activity';
  106. }
  107. protected $_stored = array();
  108. public function getStored()
  109. {
  110. $uri = $this->getUri();
  111. if (!isset($this->_stored[$uri])) {
  112. $this->_stored[$uri] = Notice::getByPK(array('uri' => $uri));
  113. }
  114. return $this->_stored[$uri];
  115. }
  116. public function getUri()
  117. {
  118. return $this->uri;
  119. }
  120. public function asActivityObject(Profile $scoped=null)
  121. {
  122. $actobj = new ActivityObject();
  123. $actobj->id = $this->getUri();
  124. $actobj->type = ActivityObject::ACTIVITY;
  125. $actobj->actor = $this->getActorObject();
  126. $actobj->target = new ActivityObject();
  127. $actobj->target->id = $this->getUri();
  128. // FIXME: actobj->target->type? as in extendActivity, and actobj->target->actor maybe?
  129. $actobj->objects = array(clone($actobj->target));
  130. $actobj->verb = ActivityVerb::DELETE;
  131. $actobj->title = ActivityUtils::verbToTitle($actobj->verb);
  132. $actor = $this->getActor();
  133. // TRANS: Notice HTML content of a deleted notice. %1$s is the
  134. // TRANS: actor's URL, %2$s its "fancy name" and %3$s the notice URI.
  135. $actobj->content = sprintf(_m('<a href="%1$s">%2$s</a> deleted notice {{%3$s}}.'),
  136. htmlspecialchars($actor->getUrl()),
  137. htmlspecialchars($actor->getFancyName()),
  138. htmlspecialchars($this->getUri())
  139. );
  140. return $actobj;
  141. }
  142. static public function extendActivity(Notice $stored, Activity $act, Profile $scoped=null)
  143. {
  144. // the original notice id and type is still stored in the Notice table
  145. // so we use that information to describe the delete activity
  146. $act->target = new ActivityObject();
  147. $act->target->id = $stored->getUri();
  148. $act->target->type = $stored->getObjectType();
  149. $act->objects = array(clone($act->target));
  150. $act->title = ActivityUtils::verbToTitle($act->verb);
  151. }
  152. static public function beforeSchemaUpdate()
  153. {
  154. $table = strtolower(get_called_class());
  155. $schema = Schema::get();
  156. $schemadef = $schema->getTableDef($table);
  157. // 2015-12-31 If we have the act_uri field we want to remove it
  158. // since there's no difference in delete verbs and the original URI
  159. // but the act_created field stays.
  160. if (!isset($schemadef['fields']['act_uri']) && isset($schemadef['fields']['act_created'])) {
  161. // We don't have an act_uri field, and we also have act_created, so no need to migrate.
  162. return;
  163. } elseif (isset($schemadef['fields']['act_uri']) && !isset($schemadef['fields']['act_created'])) {
  164. throw new ServerException('Something is wrong with your database, you have the act_uri field but NOT act_created in deleted_notice!');
  165. }
  166. if (!isset($schemadef['fields']['act_created'])) {
  167. // this is a "normal" upgrade from StatusNet for example
  168. echo "\nFound old $table table, upgrading it to add 'act_created' field...";
  169. $schemadef['fields']['act_created'] = array('type' => 'datetime', 'not null' => true, 'description' => 'datetime the notice record was created');
  170. $schemadef['fields']['uri']['length'] = 191; // we likely don't have to discover too long keys here
  171. $schema->ensureTable($table, $schemadef);
  172. $deleted = new Deleted_notice();
  173. // we don't actually know when the notice was created for the old ones
  174. $deleted->query('UPDATE deleted_notice SET act_created=created;');
  175. } else {
  176. // 2015-10-03 For a while we had act_uri and act_created fields which
  177. // apparently wasn't necessary.
  178. echo "\nFound old $table table, upgrading it to remove 'act_uri' field...";
  179. // we stored what should be in 'uri' in the 'act_uri' field for some night-coding reason.
  180. $deleted = new Deleted_notice();
  181. $deleted->query('UPDATE deleted_notice SET uri=act_uri;');
  182. }
  183. print "DONE.\n";
  184. print "Resuming core schema upgrade...";
  185. }
  186. function insert()
  187. {
  188. $result = parent::insert();
  189. if ($result === false) {
  190. common_log_db_error($this, 'INSERT', __FILE__);
  191. // TRANS: Server exception thrown when a stored object entry cannot be saved.
  192. throw new ServerException('Could not save Deleted_notice');
  193. }
  194. }
  195. }