Created
September 30, 2013 14:17
-
-
Save psaia/6764490 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mongoose = require 'mongoose' | |
helpers = require '../libs/helpers' | |
events = require "../libs/events" | |
config = require "../config" | |
async = require "async" | |
types = | |
STATUS: "status" | |
INTRODUCTION: "introduction" | |
NOTIFICATION: "notification" | |
populateMap = {} | |
populateMap[types.STATUS] = "by" | |
populateMap[types.INTRODUCTION] = "user1 user2 mutual" | |
populateMap[types.NOTIFICATION] = "for context_user context_user_2" | |
Story = new mongoose.Schema | |
created: { type: Date, default: Date.now, required: true } | |
scope: | |
public: { type: Boolean, default: false, required: true } | |
network: { type: Boolean, default: false, required: true } | |
connections: { type: Boolean, default: true, required: true } | |
custom: { type: Boolean, default: false, required: true } | |
scopedUsers: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }] | |
deleted: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }] | |
type: { type: String, required: true, enum: [types.STATUS, types.INTRODUCTION, types.NOTIFICATION] } | |
story: { type: mongoose.Schema.Types.ObjectId, required: true } | |
getDoc = (type, _id, fn) -> | |
Introduction = require "./introduction" | |
Status = require "./status" | |
Notification = require "./notification" | |
switch type | |
when types.STATUS then _Model = Status | |
when types.INTRODUCTION then _Model = Introduction | |
when types.NOTIFICATION then _Model = Notification | |
# Populate the document with necessary properies. | |
_Model.findOne({ _id: _id }).populate(populateMap[type]).exec (err, doc) -> | |
return fn err if err | |
return fn null, false if not doc | |
if type is types.STATUS # If the document is a status: | |
doc.by.populate "avatar", (err, u) -> | |
return fn err if err | |
doc.by = u | |
fn err, doc | |
else if type is types.NOTIFICATION # If the document is a notification: | |
async.waterfall [ | |
(done) -> | |
return fn(null, false) if not doc.for | |
doc.for.populate "avatar", (err, u) -> | |
return done err if err | |
doc.for = u | |
done() | |
(done) -> | |
return done() if not doc.context_user | |
doc.context_user.populate "avatar", (err, u) -> | |
return done err if err | |
doc.context_user = u | |
done() | |
(done) -> | |
return done() if not doc.context_user_2 | |
doc.context_user_2.populate "avatar", (err, u) -> | |
return done err if err | |
doc.context_user_2 = u | |
done(null) | |
], (err, result) -> fn err, doc | |
else if type is types.INTRODUCTION # If the document is a introduction: | |
async.waterfall [ | |
(done) -> | |
doc.user1.populate "avatar", (err, u) -> | |
return done err if err | |
doc.user1 = u | |
done() | |
(done) -> | |
doc.user2.populate "avatar", (err, u) -> | |
return done err if err | |
doc.user2 = u | |
done() | |
(done) -> | |
doc.mutual.populate "avatar", (err, u) -> | |
return done err if err | |
doc.mutual = u | |
done() | |
], (err, result) -> fn err, doc | |
userPermitted = (type, doc, story, owner, viewer, isOwner, pub, network) -> | |
Introduction = require "./introduction" | |
Status = require "./status" | |
Notification = require "./notification" | |
if type is types.NOTIFICATION and not pub # Only show notifications if you are looking at your own wall. | |
return false if doc.for._id.equals(owner._id) and doc.type is Notification.types.FRIEND_REGISTERED and doc.context_user and doc.context_user._id and doc.context_user._id.equals(owner._id) # This is rare. Because of merging, this prevents a notification about yourself. | |
return doc.for._id.equals owner._id # ... And if they belong to you. | |
if type is types.STATUS # Statuses are way more complicated. | |
if pub and isOwner # If your looking at your own PUBLIC wall. | |
if doc.by._id.equals(owner._id) # Only show statuses that you made and that are public.. as others would see it. | |
return true if story.scope.public or story.scope.network or story.scope.connections | |
else if pub and not isOwner # If you are looking at someone elses wall. | |
if doc.by._id.equals(owner._id) # If the owner of the page made the status. | |
return true if story.scope.public # If it's public, always show. | |
if story.scope.connections # If public for owner's connections... | |
return true if helpers.objectIdExists viewer._id, owner.connections # Make sure the viewer is in the connections. | |
else if story.scope.network # If public to owner's network... | |
return true if helpers.objectIdExists viewer._id, network # Make sure the viewer is in the owner's network. | |
else if story.scope.custom | |
return true if helpers.objectIdExists viewer._id, story.scopedUsers # Make sure the viewer is in the allowed scope of users. | |
else if not pub # You are looking at YOUR OWN wall. | |
return true if doc.by._id.equals(owner._id) # If I own it, obviously. | |
return true if story.scope.public # Which is like never. | |
if story.scope.connections # If scope is for connection only. | |
return true if helpers.objectIdExists doc.by._id, owner.connections # Make sure the doc is in the owner's connections. | |
else if story.scope.network # If scope is for connection only. | |
return true if helpers.objectIdExists doc.by._id, network # Make sure the doc owner is in the owner's network. | |
else if story.scope.custom # If the story is only for specific users. | |
return true if helpers.objectIdExists owner._id, story.scopedUsers # Make sure the owner is in the scope of users. | |
if type is types.INTRODUCTION # So are introductions... However, all introductions are same level of privacy. Better. | |
if pub # If looking at a public wall. | |
return false if doc.type is "request" # Never show requests publicly. | |
if doc.user1_accepted and doc.user2_accepted and doc.type isnt "request" | |
if doc.user1._id.equals(owner._id) or doc.user2._id.equals(owner._id) or doc.mutual._id.equals(owner._id) # Only show accepted requests. | |
return true if isOwner or helpers.objectIdExists viewer._id, owner.connections # Make sure it's either the owner or the viewer is in the owner's connections. | |
else if isOwner | |
if doc.type is "request" | |
if owner._id.equals(doc.mutual._id) | |
return true | |
if owner._id.equals(doc.user1._id) | |
return true | |
return false | |
if doc.user1._id.equals(owner._id) or doc.user2._id.equals(owner._id) | |
if doc.user1_ignored or doc.user2_ignored | |
return false | |
else | |
return true | |
else if doc.mutual._id.equals(owner._id) | |
return true | |
Story.statics.types = types | |
Story.statics.list = (owner, viewer, pub = false, args = {}, fn = ->) -> | |
options = helpers.defaults args, | |
limit: 10 | |
offset: 0 | |
type: false | |
isOwner = owner._id.toString() is viewer._id.toString() | |
list = [] | |
query = | |
deleted: | |
$nin: [owner._id] | |
if pub | |
query.$or = [ | |
{ type: types.INTRODUCTION } | |
{ type: types.STATUS } | |
] | |
if options.type and isOwner | |
if types[options.type.toUpperCase()] | |
delete query.$or if query.$or | |
query.type = options.type | |
reduce = (stories, network) -> | |
counter = 0 | |
addedStories = 0 | |
next = -> | |
story = stories[counter] | |
if story | |
getDoc story.type, story.story, (err, doc) -> # Get full populated relevant document. | |
return fn err if err | |
return next(counter++) if not doc | |
if userPermitted story.type, doc, story, owner, viewer, isOwner, pub, network | |
doc.story_id = story._id | |
list.push doc | |
addedStories++ | |
next counter++ | |
else | |
next counter++ | |
else # At the end, return array. | |
fn null, list.slice(options.offset, options.limit+options.offset) | |
next() | |
owner.getNetworkBasic (err, network) -> | |
Model.find query, null, { sort: { created: -1 } }, (err, stories) -> | |
return fn err if err | |
process.nextTick -> reduce stories, network | |
# Create the model. | |
module.exports = Model = mongoose.model 'Story', Story |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment