models.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. const ObjectID = require("mongodb").ObjectID;
  2. const {connect} = require('mm')
  3. module.exports = async (dbName='graphql-chat') => {
  4. const {Savable, slice} = await connect(dbName)
  5. async function getModels({id, acl}, onMsgSave, onChatSave){
  6. const thisUser = id !== 'anon' && await Savable.m.User.findOne({_id: ObjectID(id)})
  7. const chatACL = thisUser && thisUser.chats && thisUser.chats.map && thisUser.chats.map(c => c._id.toString())
  8. const SlicedSavable = slice(id === 'anon' ? [id] : [...acl, ...chatACL])
  9. class User extends SlicedSavable {
  10. constructor(...params){
  11. super(...params)
  12. this.originalACL = this.acl && [...this.acl]
  13. this.chats = Savable.arrize(this.chats)
  14. }
  15. async save(...params){
  16. console.log(this)
  17. let otherUserWithThisLogin = this.login && await Savable.m.User.findOne({login: this.login})
  18. if (this._id){
  19. if (otherUserWithThisLogin && otherUserWithThisLogin._id.toString() !== this._id.toString()){
  20. throw new ReferenceError(`User ${this.login} already exists`)
  21. }
  22. if (!acl.includes('admin') && this.originalACL.toString() !== this.acl.toString())
  23. throw new ReferenceError(`Not enough permissions for changing acl on ${this.login}`)
  24. else return await super.save(...params)
  25. }
  26. else {
  27. if (otherUserWithThisLogin){
  28. throw new ReferenceError(`User ${this.login} already exists`)
  29. }
  30. await super.save(...params)
  31. this.___owner = this._id.toString()
  32. this.acl = [this.___owner, "user"]
  33. return await Savable.prototype.save.call(this, ...params)
  34. }
  35. }
  36. static get relations(){ //don't needed due to ___owner in most cases
  37. return {
  38. avatar : "userAvatar",
  39. chats: ["members"]
  40. }
  41. }
  42. static get defaultPermissions(){
  43. return {
  44. create: ['anon'],
  45. read: ['owner', 'user', 'admin'],
  46. write: ['owner', 'admin'],
  47. delete: []
  48. }
  49. }
  50. static get guestRelations(){
  51. return ["chats"];
  52. }
  53. }
  54. SlicedSavable.addClass(User)
  55. class OwnerSlicedSavable extends SlicedSavable {
  56. get owner(){
  57. if (!this.___owner) return this.___owner
  58. return SlicedSavable.m.User.findOne({_id: ObjectID(this.___owner)})
  59. }
  60. }
  61. class Media extends OwnerSlicedSavable {
  62. constructor(...params){
  63. super(...params)
  64. }
  65. static async fromFileData(fileData){
  66. let media = new Media({})
  67. media.fileData = fileData
  68. media.url = `images/${fileData.filename}`
  69. media.originalFileName = fileData.originalname
  70. media.type = fileData.mimetype
  71. await media.save()
  72. return media;
  73. }
  74. //async save(...params){
  75. //if (this.userAvatar){
  76. //if (this.userAvatar._id.toString() !== id){
  77. //throw new ReferenceError(`You can't set ava for other user`)
  78. //}
  79. //}
  80. //return await super.save(...params)
  81. //}
  82. static get relations(){
  83. return {
  84. userAvatar: "avatar", //if it is ava
  85. chatAvatars: "avatar",
  86. messages: ["media"]
  87. }
  88. }
  89. static get defaultPermissions(){
  90. return {
  91. create: ['user', 'admin'],
  92. read: ['anon', 'user', 'admin'],
  93. write: ["owner", 'admin'],
  94. delete: ['admin']
  95. }
  96. }
  97. }
  98. SlicedSavable.addClass(Media)
  99. class Message extends OwnerSlicedSavable {
  100. async save(...params){
  101. if (!this.chat){
  102. throw new ReferenceError("You should set chat")
  103. }
  104. const chatId = this.chat._id.toString()
  105. if (!chatACL.includes(chatId)) {
  106. throw new ReferenceError("You cannot post to chat without membership.")
  107. }
  108. this.___permissions.read.push(chatId)
  109. this.___permissions.read = [...new Set(this.___permissions.read)]
  110. let newMsg = !this._id
  111. let result = await super.save(...params)
  112. await this.chat
  113. if (newMsg){
  114. this.chat.lastModified = this.createdAt.getTime()
  115. }
  116. await Savable.prototype.save.call(this.chat)
  117. onMsgSave(this)
  118. return result
  119. }
  120. static get relations(){
  121. return {
  122. media: ['messages'],
  123. replyTo: ['replies'],
  124. replies: 'replyTo',
  125. forwardWith: 'forwarded',
  126. forwarded: ['forwardWith'],
  127. chat: ['messages']
  128. }
  129. }
  130. static get defaultPermissions(){
  131. return {
  132. create: ['user', 'admin'],
  133. read: ['owner', 'admin'],
  134. write: ['owner','admin'],
  135. delete: ['admin']
  136. }
  137. }
  138. static get guestRelations(){
  139. return ['replies', 'forwardWith']
  140. }
  141. }
  142. SlicedSavable.addClass(Message)
  143. class Chat extends OwnerSlicedSavable {
  144. constructor(...params){
  145. super(...params)
  146. this.members = Savable.arrize(this.members)
  147. this.messages = Savable.arrize(this.messages)
  148. }
  149. get lastMessage(){
  150. return this.messages[this.messages.length -1]
  151. }
  152. async save(...params){
  153. if (!this._id){
  154. this.members.push(thisUser)
  155. await super.save(...params)
  156. this.lastModified = this.createdAt.getTime()
  157. this.___permissions.read.push(this._id.toString())
  158. }
  159. onChatSave(this)
  160. return await super.save(...params)
  161. }
  162. static get relations(){
  163. return {
  164. members: ['chats'],
  165. messages: 'chat',
  166. avatar: ["chatAvatars"]
  167. }
  168. }
  169. static get defaultPermissions(){
  170. return {
  171. create: ['user'],
  172. read: ['owner', 'admin', 'user'],
  173. write: ['owner'],
  174. delete: []
  175. }
  176. }
  177. static get guestRelations(){
  178. return ['messages', 'members']
  179. }
  180. }
  181. SlicedSavable.addClass(Chat)
  182. return {models: { SlicedSavable, ...SlicedSavable.classes },
  183. thisUser}
  184. }
  185. return {
  186. Savable,
  187. slice,
  188. getModels
  189. }
  190. }