Invitations.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. <?php
  2. /**
  3. * @package Grav\Plugin\Login
  4. *
  5. * @copyright Copyright (C) 2014 - 2021 RocketTheme, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. */
  8. namespace Grav\Plugin\Login\Invitations;
  9. use Grav\Common\File\CompiledYamlFile;
  10. use Grav\Common\Utils;
  11. use RocketTheme\Toolbox\ArrayTraits\ArrayAccess;
  12. use RocketTheme\Toolbox\ArrayTraits\Countable;
  13. use RocketTheme\Toolbox\ArrayTraits\Iterator;
  14. /**
  15. * Invite users to the site.
  16. *
  17. * Tools to send emails for invites and handle invite registrations.
  18. */
  19. class Invitations implements \Countable, \Iterator, \ArrayAccess
  20. {
  21. use ArrayAccess;
  22. use Countable;
  23. use Iterator;
  24. /** @var static */
  25. public static $instance;
  26. /** @var string */
  27. private $inviteFile = 'user-data://accounts/invites.yaml';
  28. /** @var array|null */
  29. private $items;
  30. /** @var array|null */
  31. private $emails;
  32. public static function getInstance()
  33. {
  34. if (null === static::$instance) {
  35. static::$instance = new static();
  36. }
  37. return static::$instance;
  38. }
  39. public function __construct()
  40. {
  41. $this->items = $this->load();
  42. }
  43. public function offsetGet($offset): ?Invitation
  44. {
  45. $data = $this->items[$offset] ?? null;
  46. return $data ? new Invitation($offset, $data) :null;
  47. }
  48. public function offsetSet($offset, $value): void
  49. {
  50. if (!$value instanceof Invitation) {
  51. throw new \RuntimeException('Value has to be instance of Invitation');
  52. }
  53. if (null === $offset) {
  54. $offset = $value->token;
  55. }
  56. $this->items[$offset] = $value->toArray();
  57. }
  58. public function current(): ?Invitation
  59. {
  60. return $this->offsetGet($this->key());
  61. }
  62. public function get(string $token): ?Invitation
  63. {
  64. return $this->offsetGet($token);
  65. }
  66. public function getByEmail(string $email): ?Invitation
  67. {
  68. if (null === $this->emails) {
  69. $this->emails = [];
  70. foreach ($this->items as $token => $invite) {
  71. $this->emails[$invite['email']] = $token;
  72. }
  73. }
  74. if (isset($this->emails[$email])) {
  75. return $this->offsetGet($this->emails[$email]);
  76. }
  77. return null;
  78. }
  79. public function getByIssuer(string $email): array
  80. {
  81. $list = [];
  82. foreach ($this->items as $token => $invite) {
  83. $test = $invite['email'] ?? null;
  84. if ($email === $test) {
  85. $list[] = $this->offsetGet($token);
  86. }
  87. }
  88. return $list;
  89. }
  90. public function add(Invitation $invitation): void
  91. {
  92. $this->offsetSet(null, $invitation);
  93. }
  94. public function remove(Invitation $invitation): void
  95. {
  96. $this->offsetUnset($invitation->token);
  97. }
  98. public function removeExpired(): int
  99. {
  100. $now = time();
  101. $count = 0;
  102. foreach ($this->items as $token => $invite) {
  103. if ($invite['expiration_timestamp'] < $now) {
  104. $this->offsetUnset($token);
  105. $count++;
  106. }
  107. }
  108. return $count;
  109. }
  110. public function save(): void
  111. {
  112. $file = $this->getFile();
  113. $file->save($this->items);
  114. }
  115. public function generateToken(): string
  116. {
  117. do {
  118. $id = Utils::uniqueId(24);
  119. } while (isset($this->items[$id]));
  120. return $id;
  121. }
  122. private function load(): array
  123. {
  124. $file = $this->getFile();
  125. $data = $file->content();
  126. $file->free();
  127. return $data;
  128. }
  129. private function getFile(): CompiledYamlFile
  130. {
  131. return CompiledYamlFile::instance($this->inviteFile);
  132. }
  133. }