models.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. const ObjectID = require("mongodb").ObjectID;
  2. const {connect} = require('mm')
  3. module.exports = async (dbName='hipstagram') => {
  4. const {Savable, slice} = await connect(dbName)
  5. async function getModels({id}){
  6. const SlicedSavable = slice([id, 'user'])
  7. class User extends SlicedSavable {
  8. constructor(...params){
  9. super(...params)
  10. //TODO: calc likes count by getter (no two-way relation for this to avoid overflow on many Kilos of likes
  11. //cached like count, which incremented and decremented
  12. //
  13. //following and followers array
  14. }
  15. async getACL(){
  16. return [this._id.toString(), "user"]
  17. }
  18. static get relations(){ //don't needed due to ___owner in most cases
  19. return {
  20. avatar : "userAvatar",
  21. incomings: "to",
  22. followers: ["following"],
  23. following: ["followers"],
  24. }
  25. }
  26. static get guestRelations(){
  27. return ["followers"]
  28. }
  29. }
  30. SlicedSavable.addClass(User)
  31. class OwnerSlicedSavable extends SlicedSavable {
  32. get owner(){
  33. if (!this.___owner) return this.___owner
  34. return SlicedSavable.m.User.findOne({_id: ObjectID(this.___owner)})
  35. }
  36. }
  37. class Like extends OwnerSlicedSavable {
  38. constructor(...params){
  39. super(...params)
  40. //TODO:
  41. //entity
  42. //entityLikesCount?
  43. }
  44. static get relations(){
  45. return {
  46. }
  47. }
  48. static get defaultPermissions(){
  49. return {
  50. //savable refs, objectid's, words like 'tags' or 'roles'
  51. read: ['owner', 'user'],
  52. write: ['owner'],
  53. create: ['user'],
  54. delete: ['owner'],
  55. /*permission
  56. * TODO: permissions for read and write permissions
  57. *
  58. */
  59. }
  60. }
  61. }
  62. SlicedSavable.addClass(Like)
  63. class Post extends OwnerSlicedSavable {
  64. constructor(...params){
  65. super(...params)
  66. //TODO: calc likes count by getter (no two-way relation for this to avoid overflow on many Kilos of likes
  67. //cached like count, which incremented and decremented
  68. //
  69. }
  70. get likes(){
  71. return (async () => {
  72. let result = []
  73. for (let like of SlicedSavable.m.Like.find({'post._id': this._id}, {limit: [100], sort: ['_id', 1]})){
  74. try {await like; result.push(like) } catch(e) {}
  75. }
  76. return result;
  77. })()
  78. }
  79. static get relations(){
  80. return {
  81. images: ["posts"],
  82. comments: "post",
  83. directs: "post",
  84. collections: ["posts"]
  85. }
  86. }
  87. static get guestRelations(){
  88. return ["comments", "directs"]
  89. }
  90. static get defaultPermissions(){
  91. return {
  92. //savable refs, objectid's, words like 'tags' or 'roles'
  93. read: ['owner', 'user'],
  94. write: ['owner'],
  95. create: ['user'],
  96. delete: ['owner', 'admin'],
  97. /*permission
  98. * TODO: permissions for read and write permissions
  99. *
  100. */
  101. }
  102. }
  103. }
  104. SlicedSavable.addClass(Post)
  105. class Image extends OwnerSlicedSavable {
  106. constructor(...params){
  107. super(...params)
  108. }
  109. static async fromFileData(fileData){
  110. if (!fileData) return
  111. let image = new Image({})
  112. image.fileData = fileData
  113. image.url = `images/${fileData.filename}`
  114. image.originalFileName = fileData.originalname
  115. await image.save()
  116. return image;
  117. }
  118. async save(...params){
  119. if (this.userAvatar){
  120. if (this.userAvatar._id.toString() !== id){
  121. throw new ReferenceError(`You can't set ava for other user`)
  122. }
  123. }
  124. return await super.save(...params)
  125. }
  126. static get relations(){
  127. return {
  128. userAvatar: "avatar", //if it is ava
  129. posts: ["images"], //if in post: m2m with posts
  130. directs: "image", //if in direct: m2o with directs
  131. }
  132. }
  133. }
  134. SlicedSavable.addClass(Image)
  135. class Comment extends OwnerSlicedSavable {
  136. constructor(...params){
  137. super(...params)
  138. //TODO: calc likes count by getter (no two-way relation for this to avoid overflow on many Kilos of likes
  139. //cached like count, which incremented and decremented
  140. }
  141. get likes(){
  142. return (async () => {
  143. let result = []
  144. for (let like of SlicedSavable.m.Like.find({'comment._id': this._id}, {limit: [100], sort: ['_id', 1]})){
  145. try {await like; result.push(like) } catch(e) {}
  146. }
  147. return result;
  148. })()
  149. }
  150. static get relations(){
  151. return {
  152. post: ["comments"],
  153. answers: "answerTo",
  154. answerTo: ["answers"],
  155. }
  156. }
  157. static get guestRelations(){
  158. return ["answers"]
  159. }
  160. }
  161. SlicedSavable.addClass(Comment)
  162. class Direct extends OwnerSlicedSavable {
  163. constructor(...params){
  164. super(...params)
  165. }
  166. static get relations(){
  167. return {
  168. to: ["incomings"],
  169. image: ["directs"],
  170. likes: "entity",
  171. }
  172. }
  173. static get guestRelations(){
  174. return ["to", "likes"]
  175. }
  176. }
  177. SlicedSavable.addClass(Direct)
  178. class Collection extends OwnerSlicedSavable {
  179. constructor(...params){
  180. super(...params)
  181. }
  182. static get relations(){
  183. return {
  184. posts: "collections"
  185. }
  186. }
  187. }
  188. SlicedSavable.addClass(Collection)
  189. const thisUser = await Savable.m.User.findOne({_id: ObjectID(id)})
  190. return {models: {
  191. SlicedSavable, ...SlicedSavable.classes
  192. },
  193. thisUser}
  194. }
  195. return {
  196. Savable,
  197. slice,
  198. getModels
  199. }
  200. }