123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- const ObjectID = require("mongodb").ObjectID;
- const {connect} = require('mm')
- module.exports = async (dbName='graphql-chat') => {
- const {Savable, slice} = await connect(dbName)
- async function getModels({id, acl}, onMsgSave, onChatSave){
- const thisUser = id !== 'anon' && await Savable.m.User.findOne({_id: ObjectID(id)})
- const chatACL = thisUser && thisUser.chats && thisUser.chats.map && thisUser.chats.map(c => c._id.toString())
- const SlicedSavable = slice(id === 'anon' ? [id] : [...acl, ...chatACL])
- class User extends SlicedSavable {
- constructor(...params){
- super(...params)
- this.originalACL = this.acl && [...this.acl]
- this.chats = Savable.arrize(this.chats)
- }
- async save(...params){
- console.log(this)
- let otherUserWithThisLogin = this.login && await Savable.m.User.findOne({login: this.login})
- if (this._id){
- if (otherUserWithThisLogin && otherUserWithThisLogin._id.toString() !== this._id.toString()){
- throw new ReferenceError(`User ${this.login} already exists`)
- }
- if (!acl.includes('admin') && this.originalACL.toString() !== this.acl.toString())
- throw new ReferenceError(`Not enough permissions for changing acl on ${this.login}`)
- else return await super.save(...params)
- }
- else {
- if (otherUserWithThisLogin){
- throw new ReferenceError(`User ${this.login} already exists`)
- }
- await super.save(...params)
- this.___owner = this._id.toString()
- this.acl = [this.___owner, "user"]
- return await Savable.prototype.save.call(this, ...params)
- }
- }
- static get relations(){ //don't needed due to ___owner in most cases
- return {
- avatar : "userAvatar",
- chats: ["members"]
- }
- }
- static get defaultPermissions(){
- return {
- create: ['anon'],
- read: ['owner', 'user', 'admin'],
- write: ['owner', 'admin'],
- delete: []
- }
- }
- static get guestRelations(){
- return ["chats"];
- }
- }
- SlicedSavable.addClass(User)
- class OwnerSlicedSavable extends SlicedSavable {
- get owner(){
- if (!this.___owner) return this.___owner
- return SlicedSavable.m.User.findOne({_id: ObjectID(this.___owner)})
- }
- }
- class Media extends OwnerSlicedSavable {
- constructor(...params){
- super(...params)
- }
- static async fromFileData(fileData){
- let media = new Media({})
- media.fileData = fileData
- media.url = `images/${fileData.filename}`
- media.originalFileName = fileData.originalname
- media.type = fileData.mimetype
- await media.save()
- return media;
- }
- //async save(...params){
- //if (this.userAvatar){
- //if (this.userAvatar._id.toString() !== id){
- //throw new ReferenceError(`You can't set ava for other user`)
- //}
- //}
- //return await super.save(...params)
- //}
- static get relations(){
- return {
- userAvatar: "avatar", //if it is ava
- chatAvatars: "avatar",
- messages: ["media"]
- }
- }
- static get defaultPermissions(){
- return {
- create: ['user', 'admin'],
- read: ['anon', 'user', 'admin'],
- write: ["owner", 'admin'],
- delete: ['admin']
- }
- }
- }
- SlicedSavable.addClass(Media)
- class Message extends OwnerSlicedSavable {
- async save(...params){
- if (!this.chat){
- throw new ReferenceError("You should set chat")
- }
- const chatId = this.chat._id.toString()
- if (!chatACL.includes(chatId)) {
- throw new ReferenceError("You cannot post to chat without membership.")
- }
- this.___permissions.read.push(chatId)
- this.___permissions.read = [...new Set(this.___permissions.read)]
- let result = await super.save(...params)
- await this.chat
- this.chat.lastModified = this.createdAt.getTime()
- await Savable.prototype.save.call(this.chat)
- onMsgSave(this)
- return result
- }
- static get relations(){
- return {
- media: ['messages'],
- replyTo: ['replies'],
- replies: 'replyTo',
- forwardWith: 'forwarded',
- forwarded: ['forwardWith'],
- chat: ['messages']
- }
- }
- static get defaultPermissions(){
- return {
- create: ['user', 'admin'],
- read: ['owner', 'admin'],
- write: ['owner','admin'],
- delete: ['admin']
- }
- }
- static get guestRelations(){
- return ['replies', 'forwardWith']
- }
- }
- SlicedSavable.addClass(Message)
- class Chat extends OwnerSlicedSavable {
- constructor(...params){
- super(...params)
- this.members = Savable.arrize(this.members)
- }
- async save(...params){
- if (!this._id){
- this.members.push(thisUser)
- await super.save(...params)
- this.lastModified = this.createdAt.getTime()
- this.___permissions.read.push(this._id.toString())
- }
- onChatSave(this)
- return await super.save(...params)
- }
- static get relations(){
- return {
- members: ['chats'],
- messages: 'chat',
- avatar: ["chatAvatars"]
- }
- }
- static get defaultPermissions(){
- return {
- create: ['user'],
- read: ['owner', 'admin', 'user'],
- write: ['owner'],
- delete: []
- }
- }
- static get guestRelations(){
- return ['messages']
- }
- }
- SlicedSavable.addClass(Chat)
- return {models: { SlicedSavable, ...SlicedSavable.classes },
- thisUser}
- }
- return {
- Savable,
- slice,
- getModels
- }
- }
|