entry_types.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. const params = require('../config/params');
  2. const util = require('./util');
  3. const spliceOut = util.spliceOut;
  4. const db = require('./rethinkdb');
  5. const catsoop = require('./catsoop');
  6. class Entry {
  7. constructor(db_doc) {
  8. Object.assign(this, db_doc);
  9. }
  10. static data_skeleton(data, user) {
  11. return {
  12. location: data.location,
  13. assignment: data.assignment,
  14. state: 'unclaimed',
  15. };
  16. }
  17. render(user, users) {
  18. if (this.visible_to(user)) {
  19. const username = this.username;
  20. const real_name = users.hasOwnProperty(this.username) ? users[this.username].name : '';
  21. return Promise.resolve({
  22. data: Object.assign(
  23. {},
  24. this.data,
  25. {
  26. group: [{username, real_name}]
  27. }
  28. ),
  29. type: this.type,
  30. actions: this.actions(user),
  31. date_added: this.date_added,
  32. last_modified: this.last_modified,
  33. username: this.username,
  34. real_name,
  35. });
  36. }
  37. else {
  38. return Promise.resolve({
  39. data: {state: this.data.state},
  40. type: '',
  41. actions: [],
  42. date_added: this.date_added,
  43. last_modified: '',
  44. username: util.hash_username(this.username),
  45. real_name: '',
  46. })
  47. }
  48. }
  49. actions(user) {
  50. switch (this.data.state) {
  51. case 'claimed':
  52. if (this.data.claimant !== user.username) {
  53. return [];
  54. }
  55. return [
  56. 'disclaim',
  57. 'remove',
  58. ];
  59. case 'unclaimed':
  60. return ['claim'];
  61. }
  62. }
  63. 'claim'(user) {
  64. if (!user.permissions.has('claim')) return Promise.resolve();
  65. if (params.STAFF_CHECK_IN_REQUIRED && !user.confirmed) return Promise.resolve();
  66. return db
  67. .table('queue')
  68. .get(this.username)
  69. .replace(doc => db.branch(
  70. user.claims.size || doc('data')('claimant').default(null),
  71. doc,
  72. doc.merge({
  73. data: {
  74. state: 'claimed',
  75. claimant: user.username,
  76. claimant_real_name: user.name,
  77. },
  78. last_modified: db.now(),
  79. })
  80. ));
  81. }
  82. 'disclaim'(user) {
  83. if (!user.permissions.has('claim')) return Promise.resolve();
  84. return db
  85. .table('queue')
  86. .get(this.username)
  87. .replace(doc => db.branch(
  88. doc('data')('claimant').default(null).eq(user.username),
  89. doc.without({data: 'claimant'})
  90. .without({data: 'claimant_real_name'})
  91. .merge({
  92. data: {
  93. state: 'unclaimed',
  94. },
  95. last_modified: db.now(),
  96. }),
  97. doc
  98. ));
  99. }
  100. 'remove'(user) {
  101. return db
  102. .table('queue')
  103. .get(this.username)
  104. .replace(doc => db.branch(
  105. db.or(
  106. doc('data')('claimant').default(null).eq(user.username),
  107. doc('username').eq(user.username)
  108. ),
  109. null,
  110. doc
  111. ));
  112. }
  113. }
  114. class HelpEntry extends Entry {
  115. visible_to(user) {
  116. return user.username === this.username || !['Guest', 'Student'].includes(user.role);
  117. }
  118. }
  119. class CheckoffEntry extends Entry {
  120. constructor(db_doc) {
  121. super(db_doc);
  122. this._group = catsoop
  123. .post('/groups/get_my_group', {
  124. path: JSON.stringify(this.data.assignment.path),
  125. as: this.username,
  126. })
  127. .catch(err => ({
  128. members: [this.username],
  129. }));
  130. }
  131. render(user, users) {
  132. return this._group.then(({members}) => {
  133. return super.render(user, users).then(entry => {
  134. Object.assign(entry.data, {
  135. group: members.map(m => ({
  136. username: m,
  137. real_name: users.hasOwnProperty(m) ? users[m].name : '',
  138. })),
  139. });
  140. return entry;
  141. });
  142. });
  143. }
  144. actions(user) {
  145. let actions = super.actions(user);
  146. switch (this.data.state) {
  147. case 'claimed':
  148. if (this.data.claimant !== user.username) {
  149. return actions;
  150. }
  151. return actions.concat([
  152. 'group_checkoff',
  153. 'single_checkoff',
  154. ]);
  155. case 'unclaimed':
  156. return actions;
  157. }
  158. }
  159. visible_to(user) {
  160. return user.username === this.username || user.permissions.has('queue_view_all');
  161. }
  162. 'single_checkoff'(user) {
  163. if (!user.permissions.has('checkoff')) return Promise.resolve();
  164. return catsoop
  165. .submit(this.data.assignment.page, {
  166. names: JSON.stringify([this.data.assignment.name]),
  167. as: this.username,
  168. data: JSON.stringify({[this.data.assignment.name]: params.CATSOOP.TOKEN+','+user.username}),
  169. })
  170. .then(() => db
  171. .table('queue')
  172. .get(this.username)
  173. .replace(doc => db.branch(
  174. doc('data')('claimant').default(null).eq(user.username),
  175. null,
  176. doc
  177. ))
  178. );
  179. }
  180. 'group_checkoff'(user) {
  181. if (!user.permissions.has('checkoff')) return Promise.resolve();
  182. return this._group.then(({members}) => {
  183. return Promise.all(members.map(member => {
  184. return catsoop
  185. .submit(this.data.assignment.page, {
  186. names: JSON.stringify([this.data.assignment.name]),
  187. as: member,
  188. data: JSON.stringify({[this.data.assignment.name]: params.CATSOOP.TOKEN+','+user.username}),
  189. });
  190. }));
  191. }).then(() => db
  192. .table('queue')
  193. .get(this.username)
  194. .replace(doc => db.branch(
  195. doc('data')('claimant').default(null).eq(user.username),
  196. null,
  197. doc
  198. ))
  199. );
  200. }
  201. }
  202. module.exports = {
  203. 'help': HelpEntry,
  204. 'checkoff': CheckoffEntry,
  205. };