heartbeat.module 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. <?php
  2. /**
  3. * @file
  4. * Contains heartbeat.module.
  5. */
  6. use Drupal\Core\Routing\RouteMatchInterface;
  7. use Drupal\Core\Entity\EntityInterface;
  8. use Drupal\Core\Url;
  9. use Drupal\Core\Form\FormState;
  10. use Drupal\node\NodeInterface;
  11. use Drupal\Core\Session\AccountInterface;
  12. use Drupal\Core\Entity;
  13. use Drupal\Component\Utility\Html;
  14. use Drupal\Core\Database\Database;
  15. use Drupal\heartbeat\Entity\FILE_FIELD;
  16. use Drupal\heartbeat\Entity\Heartbeat;
  17. use GuzzleHttp\Exception\RequestException;
  18. use Drupal\heartbeat\Entity\HeartbeatType;
  19. use Drupal\heartbeat\Ajax\UpdateFeedCommand;
  20. /**
  21. * Implements hook_help().
  22. */
  23. function heartbeat_help($route_name, RouteMatchInterface $route_match) {
  24. switch ($route_name) {
  25. // Main module help for the heartbeat module.
  26. case 'help.page.heartbeat':
  27. $output = '';
  28. $output .= '<h3>' . t('About') . '</h3>';
  29. $output .= '<p>' . t('Heartbeat for Drupal 8') . '</p>';
  30. return $output;
  31. default:
  32. }
  33. }
  34. /**
  35. * Implements hook_theme().
  36. */
  37. function heartbeat_theme() {
  38. $theme = [];
  39. $theme['heartbeat'] = array(
  40. 'render element' => 'elements',
  41. 'file' => 'heartbeat.page.inc',
  42. 'template' => 'heartbeat',
  43. );
  44. $theme['heartbeat_content_add_list'] = [
  45. 'render element' => 'content',
  46. 'variables' => ['content' => NULL],
  47. 'file' => 'heartbeat.page.inc',
  48. ];
  49. $theme['heartbeat_stream'] = [
  50. 'variables' => array(
  51. 'messages' => NULL,
  52. 'zilla' => 2,
  53. )
  54. ];
  55. $theme['friend_interaction'] = [
  56. 'variables' => array(
  57. 'user' => NULL,
  58. 'flag' => NULL,
  59. 'userPic' => NULL,
  60. 'testing' => 'testing yo',
  61. )
  62. ];
  63. return $theme;
  64. }
  65. /**
  66. * Implements hook_theme_suggestions_HOOK().
  67. */
  68. function heartbeat_theme_suggestions_heartbeat(array $variables) {
  69. $suggestions = array();
  70. $entity = $variables['elements']['#heartbeat'];
  71. $sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
  72. $suggestions[] = 'heartbeat__' . $sanitized_view_mode;
  73. $suggestions[] = 'heartbeat__' . $entity->bundle();
  74. $suggestions[] = 'heartbeat__' . $entity->bundle() . '__' . $sanitized_view_mode;
  75. $suggestions[] = 'heartbeat__' . $entity->id();
  76. $suggestions[] = 'heartbeat__' . $entity->id() . '__' . $sanitized_view_mode;
  77. return $suggestions;
  78. }
  79. /**
  80. * Implements hook_entity_insert().
  81. */
  82. function heartbeat_entity_insert(EntityInterface $entity) {
  83. $bundleSaved = false;
  84. switch (true) {
  85. case $entity instanceof \Drupal\node\Entity\Node:
  86. $user = $entity->getOwner();
  87. $media = HeartBeat::mediaFieldTypes($entity->getFields());
  88. if ($entity->id() && $user->isAuthenticated()) {
  89. $heartbeatTypeService = \Drupal::service('heartbeat.heartbeattype');
  90. $tokenService = \Drupal::service('token');
  91. foreach ($heartbeatTypeService->getTypes() as $type) {
  92. $heartbeatTypeEntity = $heartbeatTypeService->load($type);
  93. if ($heartbeatTypeEntity->getMainEntity() == 'node') {
  94. $arguments = json_decode($heartbeatTypeEntity->getArguments());
  95. foreach ($arguments as $key => $argument) {
  96. $variables[$key] = $argument;
  97. }
  98. $preparsedMessageString = strtr($heartbeatTypeEntity->getMessage(), $variables);
  99. $entities = array(
  100. 'node' => $entity,
  101. 'user' => $user,
  102. );
  103. if ($entity->bundle() === $heartbeatTypeEntity->getBundle()
  104. &&
  105. array_key_exists($heartbeatTypeEntity->getBundle(), $heartbeatTypeService->getEntityBundles($entity->getEntityType()))
  106. ) {
  107. $heartbeatMessage = Heartbeat::buildMessage($tokenService, $preparsedMessageString, $entities, $entity->getEntityTypeId(), $media);
  108. $heartbeatActivity = Heartbeat::create([
  109. 'type' => $heartbeatTypeEntity->id(),
  110. 'uid' => $user->id(),
  111. 'nid' => $entity->id(),
  112. 'name' => $entity->getTitle(),
  113. ]);
  114. //TODO Find better fix than this str_replace
  115. $heartbeatActivity->setMessage(str_replace('&039;', "'", $heartbeatMessage));
  116. if ($heartbeatActivity->save()) {
  117. $bundleSaved = true;
  118. }
  119. continue;
  120. } else if ($heartbeatTypeEntity->getBundle() === null || trim($heartbeatTypeEntity->getBundle()) === '') {
  121. $heartbeatMessage = Heartbeat::buildMessage($tokenService, $preparsedMessageString, $entities, $entity->getEntityTypeId(), $media);
  122. // $translatedMessage = t($messageTemplate);
  123. $heartbeatActivity = Heartbeat::create([
  124. 'type' => $heartbeatTypeEntity->id(),
  125. 'uid' => $user->id(),
  126. 'nid' => $entity->id(),
  127. 'name' => $entity->getTitle(),
  128. 'status' => !$bundleSaved ? 1 : 0,
  129. ]);
  130. $heartbeatActivity->setMessage($heartbeatMessage);
  131. $heartbeatActivity->save();
  132. } else {
  133. continue;
  134. }
  135. }
  136. }
  137. updateFeeds();
  138. }
  139. break;
  140. case $entity instanceof \Drupal\user\Entity\User:
  141. // $userService = \Drupal\User\Entity\user
  142. break;
  143. case $entity instanceof \Drupal\flag\Entity\Flag:
  144. break;
  145. case $entity instanceof \Drupal\statusmessage\Entity\Status:
  146. $user = \Drupal\user\Entity\User::load($entity->get('uid')->getValue()[0]['target_id']);
  147. $heartbeatTypeService = \Drupal::service('heartbeat.heartbeattype');
  148. $tokenService = \Drupal::service('token');
  149. heartbeat_handle_entity($entity, $tokenService, $heartbeatTypeService, $user, 'status');
  150. break;
  151. }
  152. }
  153. function heartbeat_handle_entity($entity, $tokenService, $heartbeatTypeService, $user, $mainEntity) {
  154. $bundleSaved = false;
  155. if ($entity->id() && $user->isAuthenticated()) {
  156. $media = HeartBeat::mediaFieldTypes($entity->getFields());
  157. foreach ($heartbeatTypeService->getTypes() as $type) {
  158. $heartbeatTypeEntity = $heartbeatTypeService->load($type);
  159. if ($heartbeatTypeEntity->getMainEntity() == $mainEntity) {
  160. $arguments = json_decode($heartbeatTypeEntity->getArguments());
  161. foreach ($arguments as $key => $argument) {
  162. $variables[$key] = $argument;
  163. }
  164. $preparsedMessageString = strtr($heartbeatTypeEntity->getMessage(), $variables);
  165. $entities = array(
  166. $mainEntity => $entity,
  167. 'user' => $user,
  168. );
  169. if ($entity->bundle() === $heartbeatTypeEntity->getBundle()
  170. &&
  171. array_key_exists($heartbeatTypeEntity->getBundle(), $heartbeatTypeService->getEntityBundles($entity->getEntityType()))
  172. ) {
  173. $heartbeatMessage = Heartbeat::buildMessage($tokenService, $preparsedMessageString, $entities, $entity->getEntityTypeId(), $media);
  174. $heartbeatActivity = Heartbeat::create([
  175. 'type' => $heartbeatTypeEntity->id(),
  176. 'uid' => $user->id(),
  177. 'nid' => $entity->id(),
  178. 'name' => $entity->getTitle(),
  179. ]);
  180. $heartbeatActivity->setMessage($heartbeatMessage);
  181. if ($heartbeatActivity->save()) {
  182. $bundleSaved = true;
  183. }
  184. continue;
  185. } else if ($heartbeatTypeEntity->getBundle() === null || trim($heartbeatTypeEntity->getBundle()) === '') {
  186. $heartbeatMessage = Heartbeat::buildMessage($tokenService, $preparsedMessageString, $entities, $entity->getEntityTypeId(), $media);
  187. // $translatedMessage = t($messageTemplate);
  188. $heartbeatActivity = Heartbeat::create([
  189. 'type' => $heartbeatTypeEntity->id(),
  190. 'uid' => $user->id(),
  191. 'nid' => $entity->id(),
  192. 'name' => $entity->getName(),
  193. 'status' => !$bundleSaved ? 1 : 0,
  194. ]);
  195. $heartbeatActivity->setMessage(str_replace('&039;', "'", $heartbeatMessage));
  196. $heartbeatActivity->save();
  197. } else {
  198. continue;
  199. }
  200. }
  201. }
  202. }
  203. // updateFeeds();
  204. }
  205. function updateFeeds() {
  206. // $configFactory = \Drupal::service('config.factory');
  207. }
  208. /**
  209. * Implements hook_entity_view().
  210. */
  211. function heartbeat_entity_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode) {
  212. if ($entity instanceof \Drupal\user\Entity\User) {
  213. if (isset($build['flag_friendship']) && \Drupal::currentUser()->id() === $entity->id()) {
  214. \Drupal::logger('heartbeat_friendship_entityView')->debug('IDs are %id1 and %id2', array(
  215. '%id1' => \Drupal::currentUser()->id(),
  216. '%id2' => $entity->id(),
  217. ));
  218. unset($build['flag_friendship']);
  219. }
  220. }
  221. }
  222. /**
  223. * Implements hook_cron().
  224. */
  225. function heartbeat_cron() {
  226. //Iterate over the Heartbeat Types and ensure that the weight of bundle-specific types are lower than that of their
  227. //parent type. This will allow us to ensure Bundle specific types end up being published as opposed to
  228. //Types which represent all content types
  229. $heartbeatTypes = \Drupal::service('entity.query')->get('heartbeat_type')->condition('mainentity', 'node')->execute();
  230. foreach($heartbeatTypes as $heartbeatType) {
  231. $entity = \Drupal::service('entity_type.manager')->getStorage('heartbeat_type')->load($heartbeatType);
  232. if ($entity->getBundle() === null) {
  233. $entity->setWeight(99);
  234. $entity->save();
  235. } else {
  236. $entity->setWeight(0);
  237. $entity->save();
  238. }
  239. if ($entity->getMainEntity() === 'flagging') {
  240. $friendship = true;
  241. $flagService = \Drupal::service('flag');
  242. foreach ($flagService->getAllFlags('user') as $flag) {
  243. if ($flag->id() === 'friendship') {
  244. $flaggings = \Drupal\Core\Database\Database::getConnection()->select('flagging', 'f')
  245. ->fields('f', array('entity_id', 'uid'))
  246. ->condition('flag_id', $flag->id())->execute();
  247. foreach ($flaggings->fetchAll() as $flagging) {
  248. $friendship = \Drupal\Core\Database\Database::getConnection()->select('heartbeat_friendship', 'hf')
  249. ->fields(array('status'))
  250. ->condition('uid', $flagging->uid)
  251. ->condition('uid_target', $flagging->entity_id)
  252. ->execute();
  253. if ($friendship = $friendship->fetchObject()) {
  254. $status = $friendship->status;
  255. $revFriendship = \Drupal\Core\Database\Database::getConnection()->select('heartbeat_friendship', 'hf')
  256. ->fields(array('status'))
  257. ->condition('uid', $flagging->entity_id)
  258. ->condition('uid_target', $flagging->uid)
  259. ->execute();
  260. if ($revFriendship = $revFriendship->fetchObject()) {
  261. $revStatus = $revFriendship->status;
  262. }
  263. }
  264. }
  265. }
  266. }
  267. }
  268. // $entityQuery = \Drupal::service('entity.query')->get('flag
  269. // foreach ($flagService->)
  270. }
  271. heartbeat_friendship_maintenance();
  272. }
  273. function heartbeat_friendship_maintenance() {
  274. $flagService = \Drupal::service('flag');
  275. $entityTypeManager = \Drupal::service('entity_type.manager');
  276. $flag = $flagService->getFlagById('friendship');
  277. $friendships = Database::getConnection()->select("heartbeat_friendship", "hf")
  278. ->fields('hf', array('status', 'uid', 'uid_target'))
  279. ->execute();
  280. foreach ($friendships->fetchAll() as $friendship) {
  281. $revFriendship = Database::getConnection()->select('heartbeat_friendship', 'hf')
  282. ->fields('hf', array('status'))
  283. ->condition('uid', $friendship->uid_target)
  284. ->condition('uid_target', $friendship->uid)
  285. ->execute();
  286. $revFriendResult = $revFriendship->fetchField();
  287. if ($revFriendResult > -2) {
  288. if ($revFriendResult !== $friendship->status) {
  289. $update = Database::getConnection()->update('heartbeat_friendship')
  290. ->fields(array(
  291. ':status' => 1,
  292. )
  293. )
  294. ->condition('uid', $friendship->uid)
  295. ->condition('uid_target', $friendship->uid_target);
  296. if ($updated = !$update->execute()) {
  297. \Drupal::logger('Heartbeat Cron')->error('Could not update status for friendship');
  298. }
  299. }
  300. if ($revFriendResult === $friendship->status ||
  301. $updated) {
  302. $userEntity = $entityTypeManager->getStorage('user')->load($friendship->uid);
  303. $userTargetEntity = $entityTypeManager->getStorage('user')->load($friendship->uid_target);
  304. $flaggingFound = false;
  305. foreach ($flagService->getEntityFlaggings($flag, $userTargetEntity) as $flagging) {
  306. $flOwner = $flagging->getOwnerId();
  307. $usId = $userEntity->id();
  308. $flaggableId = $flagging->getFlaggableId();
  309. //TODO ownerId and entity Id seem to be reversed.
  310. if ($flagging->getOwnerId() == $userEntity->id() && $flagging->getFlaggableId() == $friendship->uid_target) {
  311. $flaggingFound = true;
  312. break;
  313. }
  314. }
  315. if (!$flaggingFound) {
  316. $flagging = $flagService->flag($flag, $userTargetEntity, $userEntity);
  317. }
  318. $flaggingReverseFound = false;
  319. foreach ($flagService->getEntityFlaggings($flag, $userEntity) as $flagging) {
  320. if ($flagging->getOwnerId() == $userTargetEntity->id() && $flagging->getFlaggableId() == $friendship->uid) {
  321. $flaggingReverseFound = true;
  322. break;
  323. }
  324. }
  325. if (!$flaggingReverseFound) {
  326. $flagging = $flagService->flag($flag, $userEntity, $userTargetEntity);
  327. }
  328. //TODO update flagging values or create flaggings
  329. }
  330. } else if ($friendship->status === 1) {
  331. //TODO Add reverse friendship
  332. $insertReverse = Database::getConnection()->insert('heartbeat_friendship')
  333. ->fields([
  334. 'uid' => $friendship->uid_target,
  335. 'uid_target' => $friendship->uid,
  336. 'created' => time(),
  337. 'status' => 1
  338. ]);
  339. if ($insertReverse->execute()) {
  340. if ($friendship->status < 1) {
  341. $updateFriendship = Database::getConnection()->update('heartbeat_friendship')
  342. ->fields(array(
  343. 'status' => 1,
  344. ))
  345. ->condition('uid', $friendship->uid)
  346. ->condition('uid_target', $friendship->uid_target);
  347. if (!$updateFriendship->execute()) {
  348. \Drupal::logger('Friendship update failed');
  349. }
  350. }
  351. } else {
  352. \Drupal::logger('Heartbeat')->debug('Unable to insert or update for User with ID %id', ['%id' => $friendship->uid]);
  353. }
  354. } else {
  355. //TODO figure out how to set friendship pending
  356. }
  357. }
  358. }
  359. /**
  360. * Implements hook_cron().
  361. */
  362. function heartbeat_update_type_weight() {
  363. //Iterate over the Heartbeat Types and ensure that the weight of bundle-specific types are lower than that of their
  364. //parent type. This will allow us to ensure Bundle specific types end up being published as opposed to
  365. //Types which represent all content types
  366. $heartbeatTypes = \Drupal::service('entity.query')->get('heartbeat_type')->condition('mainentity', 'node')->execute();
  367. if (count($heartbeatTypes) > 1) {
  368. foreach($heartbeatTypes as $heartbeatType) {
  369. $entity = \Drupal::service('entity_type.manager')->getStorage('heartbeat_type')->load($heartbeatType);
  370. if ($entity->getBundle() === null) {
  371. $entity->setWeight(99);
  372. $entity->save();
  373. } else {
  374. $entity->setWeight(0);
  375. $entity->save();
  376. }
  377. }
  378. }
  379. }
  380. /**
  381. * Implements hook_page_attachments_alter().
  382. */
  383. function heartbeat_page_attachments_alter(array &$attachments) {
  384. $attachments['#attached']['library'][] = 'heartbeat/heartbeat';
  385. }
  386. function heartbeat_link_alter(&$variables) {
  387. if (!is_object($variables['text']) && $variables['text'] === 'Account Settings') {
  388. $token_service = \Drupal::token();
  389. $replacement = $token_service->replace($variables['url']->getUri(), [\Drupal::currentUser()]);
  390. unset($variables['url']);
  391. $url = Url::fromUserInput('/' . substr($replacement, 5));
  392. $variables['url'] = $url;
  393. }
  394. }
  395. /**
  396. * Implements hook_form_alter().
  397. */
  398. function heartbeat_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  399. $form['#attached']['drupalSettings']['admin'] = in_array('administrator', \Drupal::currentUser()->getRoles());
  400. }