def toDictionary(self, options=[], user=None): '''For packaging JSON objects Pass in list of VisionComment.Options.* for extra information ''' objs = [] commentList = self._commentModels if self.length() > 0: from Picture import Picture idToPicture = dict() if VisionComment.Options.PICTURE in options: pictureIds = set([c.pictureId() for c in self.comments()]) pictureIds.discard(0) pictures = Picture.getByIds(pictureIds) idToPicture = dict([(picture.id(), picture) for picture in pictures]) if VisionComment.Options.AUTHOR in options: authorIds = set([comment.authorId() for comment in self.comments()]) authors = DataApi.getUsersFromIds(authorIds) idToAuthor = dict([(u.id, u) for u in authors]) # If LIKES if VisionComment.Options.LIKES in options: commentIds = [c.id() for c in self.comments()] tuples = DataApi.getVisionCommentListLikeCount(commentIds) idToLikeCount = dict([(commentId, count) for commentId, count in tuples]) if user: commentUserLikes = DataApi.getVisionCommentIdsLikedByUser( commentIds, user.id()) for comment in commentList: obj = VisionComment(comment).toDictionary() if VisionComment.Options.AUTHOR in options: from User import User author = idToAuthor[comment.authorId] obj[VisionComment.Key.AUTHOR] = User(author).toDictionary() # If LIKES if VisionComment.Options.LIKES in options: obj[VisionComment.Key.LIKE] = \ { VisionComment.Key.LIKE_COUNT : idToLikeCount[comment.id] if comment.id in idToLikeCount else 0 } if user: obj[VisionComment.Key.LIKE]\ [VisionComment.Key.USER_LIKE] =\ comment.id in commentUserLikes if VisionComment.Options.PICTURE in options: if comment.pictureId > 0 and \ comment.pictureId in idToPicture: cp = idToPicture[comment.pictureId] obj[VisionComment.Key.PICTURE] = cp.toDictionary() objs.append(obj) return objs
def setInfo(self, firstName, lastName, email, visionPrivacy): '''Returns True if something changed, else False''' change = False if Verifier.nameValid(firstName) and \ Verifier.nameValid(lastName) and \ Verifier.emailValid(email): change |= DataApi.setUserName(self.model(), firstName, lastName) change |= DataApi.setUserEmail(self.model(), email) change |= DataApi.setUserVisionPrivacy(self.model(), visionPrivacy) return change
def getById(visionId, inquiringUser): '''Get vision by id with privileges of inquiringUser, else None. If inquiringUser==None, assume public is trying to access this vision. ''' model = DataApi.getVision(visionId) if DataApi.NO_OBJECT_EXISTS == model: return None vision = Vision(model) # Ensure that user can access this vision relationship = Relationship.get( inquiringUser.id() if inquiringUser else None, vision.userId()) ok = False if Relationship.NONE == relationship: # if no relationship, vision must be public if VisionPrivacy.PUBLIC == vision.privacy(): ok = True elif Relationship.SELF == relationship: # if it is your own vision, you def have access ok = True if True == ok: return vision else: return None
def addVision(self, imageUrl, text, isUploaded, isPublic): '''Creates new vision TODO: What does isUploaded mean? Returns (Vision/None, None or error_msg if add vision failed) ''' #TODO: Save page title and page URL? if imageUrl == "": return [None, "No image"] if len(text.strip()) <= 0: return [None, "No text"] pictureId, errorMsg = self._processAndUploadImageUrl(imageUrl, isUploaded) if pictureId == None: return [None, "Error saving picture"] privacy = VisionPrivacy.PUBLIC if not isPublic: privacy = VisionPrivacy.PRIVATE visionId = DataApi.addVision(self.model(), text, pictureId, 0, 0, privacy) if visionId == DataApi.NO_OBJECT_EXISTS_ID: return [None, "Error creating vision"] vision = Vision.getById(visionId, self) if vision: return [vision, "Saved Vision!"] else: return [None, "Error retrieving vision"]
def toDictionary(self, options=[], user=None): '''To dictionary''' # Remeber not to use 'user' because it is a parameter idToUser = dict([(u.id(), u) for u in self.users()]) # If we need to, fetch Follows to check if there are return follows # for if people in userIds follow the user passed in as a parameter if user and UserList.Options.USER_FOLLOW in options: userFollows = DataApi.getUserFollowsFromList(user.model(), idToUser.keys()) userFollowIds = [f.userId for f in userFollows] from Follow import Follow idToFollow = dict([(f.userId, Follow(f)) for f in userFollows]) objList = [] for u in self.users(): obj = u.toDictionary() if user and UserList.Options.USER_FOLLOW in options: if u.id() in idToFollow: follow = idToFollow[u.id()] obj[User.Key.BLESSED] = follow.blessed(user) obj[User.Key.FOLLOW] = True else: obj[User.Key.BLESSED] = False obj[User.Key.FOLLOW] = False objList.append(obj) return objList
def _processAndUploadImageUrl(self, imageUrl, isUploaded): if imageUrl == "": return [None, "No image"] imageUpload = ImageUrlUpload(imageUrl) s3Vision = imageUpload.saveAsVisionImage(self.id()) if None == s3Vision: return [None, "Invalid image"] pictureId = DataApi.addPicture(self.model(), imageUrl, isUploaded, s3Vision.s3Bucket(), s3Vision.origKey(), s3Vision.origWidth(), s3Vision.origHeight(), s3Vision.largeKey(), s3Vision.largeWidth(), s3Vision.largeHeight(), s3Vision.mediumKey(), s3Vision.mediumWidth(), s3Vision.mediumHeight(), s3Vision.smallKey(), s3Vision.smallWidth(), s3Vision.smallHeight()) if pictureId == DataApi.NO_OBJECT_EXISTS_ID: return [None, "Error saving picture"] return [pictureId, "Success"]
def getFromVision(vision, maxComments): '''Get comment list from vision with max number, else None. NOTE: This assumes the user is vetted to access this vision. ''' models = DataApi.getVisionComments(vision.model(), maxComments) return VisionCommentList._getWithModels(models)
def getUserVisions(user, targetUser): '''Gets vision of targetUser that are accessible by user. If user is None, it will treat it as public access. ''' assert targetUser, "Invalid target user" userId = None if user: userId = user.id() models = DataApi.getVisionsForUser(targetUser.model()) # determine relationship for filtering viewable visions relationship = Relationship.get(userId, targetUser.id()) if Relationship.NONE == relationship: # If no relationship, only show public visions filtered = [] for model in models: if model.privacy == VisionPrivacy.PUBLIC: filtered.append(model) return VisionList(filtered) elif Relationship.SELF == relationship: # Show all visions return VisionList(models) else: assert False, "Invalid relationship value" return None
def getById(pictureId): '''Get picture by id, else None''' if pictureId > 0: model = DataApi.getPicture(pictureId) if DataApi.NO_OBJECT_EXISTS != model: return Picture(model) return None
def get(comment, user): '''Get VisionCommentLike or None''' if user == None: return None model = DataApi.getVisionCommentLike(comment.model(), user.model()) if model == DataApi.NO_OBJECT_EXISTS: return None return VisionCommentLike(model)
def getByIds(visionIds, allowRemovedVisions=False): '''Note that this assumes we have access to all these visions. MUST do privacy checks before calling. ''' models = DataApi.getVisionsById(visionIds, allowRemovedVisions=allowRemovedVisions) return VisionList(models)
def followUser(self, user): '''Returns new follow, or None''' if self.id() == user.id(): return None followModel = DataApi.addFollow(self.model(), user.model()) if followModel: from ..WorkerJobs import Queue_followEmail Queue_followEmail(self.toDictionary(), user.toDictionaryFull()) return Follow(followModel)
def getRecentVisionActivity(user): """Get list of visions we want to display from the recent activities""" # Get list of potential visions activities = DataApi.getRecentActivities() commentIds = set([a.objectId for a in activities if a.action == Activity.Action.COMMENT_ON_VISION]) commentModels = DataApi.getVisionCommentsById(commentIds) idToComment = dict([(c.id, c) for c in commentModels]) visionIds = set([a.objectId for a in activities if a.action == Activity.Action.ADD_VISION]) for c in commentModels: visionIds.add(c.visionId) visionModels = DataApi.getVisionsById(visionIds, allowRemovedVisions=True) idToVision = dict([(v.id, v) for v in visionModels]) # Now create ordered list without visions that have a duplicate # root vision, and without private visions rootIds = set() orderedVisions = [] for a in activities: vision = None if a.action == Activity.Action.ADD_VISION: if a.objectId in idToVision: vision = idToVision[a.objectId] elif a.action == Activity.Action.COMMENT_ON_VISION: if a.objectId in idToComment: comment = idToComment[a.objectId] if comment.visionId in idToVision: vision = idToVision[comment.visionId] if ( vision and vision.removed == False and vision.privacy == VisionPrivacy.PUBLIC and vision.rootId not in rootIds ): orderedVisions.append(vision) rootIds.add(vision.rootId) return VisionList(orderedVisions)
def edit(self, text, isPublic): '''Set new text and/or privacy value Returns (True if change happened, error_msg if there is one) ''' # Make sure text is valid text = text.strip() if len(text) < 0: return (False, "Text field is required.") # Make sure to maintain privacy! If already private, can't change to # public! if False == self.isPublic() and \ True == isPublic and \ DataApi.visionHasCommentsFromOthers(self.model(), self.userId()): return (False, "Can't make vision public once there are comments from others.") # ok, now we can make the change privacy = VisionPrivacy.PRIVATE if isPublic: privacy = VisionPrivacy.PUBLIC return (DataApi.editVision(self.model(), text, privacy), "")
def setProfilePicture(self, file): '''Sets profile picture from file input stream Returns URL on success, else None ''' image = ProfilePicture(file) url = None if file and image.isImage(): url = image.uploadToS3(self.id()) if url != None: if True == DataApi.setProfilePicture(self.model(), url): return url return None
def addComment(self, user, text, pictureId=0): '''Return new comment, or None. Note: Assumes vision is already vetted to be written by user.''' if len(text.strip()) > 0 or pictureId > 0: commentModel = DataApi.addVisionComment(self.model(), user.model(), text, pictureId) if DataApi.NO_OBJECT_EXISTS == commentModel: return None else: return VisionComment._getByModel(commentModel) return None
def like(self, user): '''Returns true if successful, false otherwise''' like = DataApi.addVisionLike(self.model(), user.model()) if like: # If liker is different from owner of vision, email the owner if user.id() != self.userId(): from ..WorkerJobs import Queue_visionLikeEmail owner = self.user() if owner: Queue_visionLikeEmail(owner.toDictionaryFull(), user.toDictionary(), self.toDictionary()) return True return False
def like(self, user): '''Returns true if successful, false otherwise''' like = DataApi.addVisionCommentLike(self.model(), user.model()) if like: # If liker different than author, email the author of the comment if user.id() != self.authorId(): from ..WorkerJobs import Queue_visionCommentLikeEmail author = self.author() if author: vision = self.vision(user) if vision: Queue_visionCommentLikeEmail( author.toDictionaryFull(), user.toDictionary(), vision.toDictionary(), self.toDictionary()) return True return False
def repostVision(self, vision): '''Repost a vision and return new vision if successful, else None''' assert vision, "Invalid vision" isPublic = self.visionDefaultIsPublic() newVisionId = DataApi.repostVision(self.model(), vision.model(), isPublic) if DataApi.NO_OBJECT_EXISTS_ID != newVisionId: newVision = Vision.getById(newVisionId, self) if newVision: # Only let original user know if this vision is posted # publicly if isPublic: from ..WorkerJobs import Queue_repostEmail Queue_repostEmail(self.toDictionary(), vision.toDictionary(), newVision.toDictionary()) return newVision return None
def toDictionary(self, options=[], user=None): '''To dictionary''' from User import User # get list of user ids we want to fetch if FollowList.Options.FOLLOW_LIST in options: userIds = [follow.userId() for follow in self.followList()] elif FollowList.Options.FOLLOWER_LIST in options: userIds = [follow.followerId() for follow in self.followList()] else: assert False, "Should have FOLLOW_LIST or FOLLOWER_LIST options" users = User.getByUserIds(userIds) # don't user 'user' because it is a parameter idToUser = dict([(u.id(), u) for u in users]) # If we need to, fetch Follows to check if there are return follows # for if people in userIds follow the user passed in as a parameter if FollowList.Options.USER_FOLLOW in options: userFollows = DataApi.getUserFollowsFromList(user.model(), userIds) userFollowIds = [f.userId for f in userFollows] objList = [] for follow in self.followList(): if FollowList.Options.FOLLOW_LIST in options: u = idToUser[follow.userId()] elif FollowList.Options.FOLLOWER_LIST in options: u = idToUser[follow.followerId()] else: assert False, "Should have FOLLOW_LIST or FOLLOWER_LIST options" obj = u.toDictionary() obj[User.Key.BLESSED] = follow.blessed(user) if FollowList.Options.USER_FOLLOW in options: obj[User.Key.FOLLOW] = u.id() in userFollowIds objList.append(obj) return objList
def getUserFollowers(user, number=0): '''Get list of Follow objects of people following this user''' models = DataApi.getUserFollowers(user.model(), number) return FollowList(models)
def getAllUsers(): '''Gets a list of Users from a list of userIds''' models = DataApi.getAllUsers() return [User(model) for model in models]
def getByUserIds(userIds): '''Gets a list of Users from a list of userIds''' models = DataApi.getUsersFromIds(userIds) return [User(model) for model in models]
def getByEmail(email): '''Get user by email or None''' model = DataApi.getUserByEmail(email) if DataApi.NO_OBJECT_EXISTS == model: return None return User(model)
def getById(userId): '''Get user by user id or None ''' model = DataApi.getUserById(userId) if DataApi.NO_OBJECT_EXISTS == model: return None return User(model)
def _registerNewUser(firstName, lastName, email, passwordText): '''Registers and returns new user Returns (User if successful or None, error_msg if not successful) ''' firstName = firstName.strip() lastName = lastName.strip() email = email.strip().lower() passwordText = passwordText.strip() errorMsg = None if len(firstName) <= 0: errorMsg = RegisterError.FIRST_NAME_REQUIRED elif not Verifier.nameValid(firstName): errorMsg = RegisterError.FIRST_NAME_INVALID elif len(lastName) <= 0: errorMsg = RegisterError.LAST_NAME_REQUIRED elif not Verifier.nameValid(lastName): errorMsg = RegisterError.LAST_NAME_INVALID elif len(email) <= 0: errorMsg = RegisterError.EMAIL_REQUIRED elif not Verifier.emailValid(email): errorMsg = RegisterError.EMAIL_INVALID elif len(passwordText) <= 0: errorMsg = RegisterError.PASSWORD_REQUIRED elif not Verifier.passwordValid(passwordText): errorMsg = RegisterError.PASSWORD_INVALID else: user = User.getByEmail(email) if user: errorMsg = RegisterError.EMAIL_TAKEN if errorMsg == None: passwordHash = PasswordEncrypt.genHash(passwordText) Logger.debug("Name: %s %s, Email: %s, Pass: %s [%s]" % \ (firstName, lastName, email, passwordText, passwordHash)) # Just need to add new user here and login userId = DataApi.addUser(firstName, lastName, email, passwordHash) user = User.getById(userId) if user: # Auto-follow founders so we know who joined, they have # someone in their feed, they know how to connect to founders, # and can look at us as an example of how to use the site. alex = User.getAlex() nikil = User.getNikil() if alex: user.followUser(alex) if nikil: user.followUser(nikil) # Send welcome email from ..WorkerJobs import Queue_welcomeEmail Queue_welcomeEmail(user.toDictionaryFull()) return (user, None) else: return (None, RegisterError.DB_ERROR) else: return (None, errorMsg)
def unfollowUser(self, user): '''Remove an existing follow''' if self.id() == user.id(): return False return DataApi.removeFollow(self.model(), user.model())
def deleteVision(self, visionId): '''Returns True if delete worked, False if it failed''' return DataApi.deleteUserVision(self.model(), visionId)
def moveVision(self, visionId, srcIndex, destIndex): '''Returns True if move worked, False if it failed''' return DataApi.moveUserVision(self.model(), visionId, srcIndex, destIndex)
def setDescription(self, description): '''Returns True if description changed, else False''' return DataApi.setUserDescription(self.model(), description.strip())