def set_grade_assignment(P, req): uid = UR.getUserId(req) if not auth.canGrade(uid, P["id_source"], P["id_user"]): return UR.prepare_response({}, 1, "NOT ALLOWED") retval = {} retval["grades"] = annotations.set_grade_assignment(uid, {"id_source": P["id_source"], "id_user": P["id_user"], "grade": P["grade"]}) return UR.prepare_response(retval)
def run(req): r = HttpResponse() r["Access-Control-Allow-Origin"]="*" try: if req.method == "OPTIONS" or len(req.POST)==0: #FF3 trying to check if Cross Site Request allowed. return r else: #rpc request: fctname = req.POST["f"] payload = json.loads(req.POST["a"]) cid = req.POST["cid"] if cid == "0" or cid == 0: cid = datetime.datetime.now() signals.register_session.send("rpc", cid=cid,req=req) UR.CID = cid MODULE = sys.modules[__name__] if fctname in __EXPORTS: r.content = getattr(MODULE, fctname)(payload, req) return r else: assert False, "[PDF] method '%s' not found in __EXPORTS" % fctname r.content = UR.prepare_response({}, 1,"[PDF] method '%s' not found in __EXPORTS" % fctname) return r except IOError: logging.error("[rpc.views.run] IOError") r.content = UR.prepare_response({}, 1,"I/O Error") return r
def set_comment_label(P, req): uid = UR.getUserId(req) cid = P["comment_id"] if not auth.canLabelComment(uid, cid): return UR.prepare_response({}, 1, "NOT ALLOWED") record = None try: record = M.CommentLabel.objects.get(grader__id=uid, comment__id=cid, category_id=P["category_id"]) rh = M.CommentLabelHistory() rh.grader = record.grader rh.ctime = record.ctime rh.grade = record.grade rh.category = record.category rh.comment = record.comment rh.save() record.ctime = datetime.datetime.now() except M.CommentLabel.DoesNotExist: record = M.CommentLabel() record.category_id = P["category_id"] record.comment_id = cid record.grade = P["grade"] record.grader_id = uid record.save() retval = {"commentlabels":{record.id: UR.model2dict(record)}} return UR.prepare_response(retval)
def log_history(payload, req): uid = UR.getUserInfo(req, True).id if uid is None: #SACHA TODO: LOG this. return UR.prepare_response({}, 1, "NOT ALLOWED") cid = UR.CID if cid == 0: return UR.prepare_response({}, 1, "CID MOST BE NONZERO") session, previous_activity = annotations.markActivity(cid) if session is None: return UR.prepare_response({}, 1, "SESSION NOT FOUND") id_session = session.id output={} if "seen" in payload and cid != 0: annotations.markCommentSeen(uid, id_session, payload["seen"]) if "page" in payload and cid != 0: annotations.markPageSeen(uid, id_session, payload["page"]) if "idle" in payload and cid != 0: annotations.markIdle(uid, id_session, payload["idle"]) if "scrolling" in payload and cid != 0: logger = logging.getLogger("scrolling") logger.info("%s|%s"%(id_session, payload["scrolling"])); if "__return" in payload and cid != 0: R = payload["__return"] if R["type"] == "newNotesOnFile": id_source = R["a"]["id_source"] if auth.canReadFile(uid, id_source): output["locations"], output["html5locations"], output["comments"], output["threadmarks"] = annotations.getCommentsByFile(id_source, uid, previous_activity) elif R["type"] == "newPending": #for now, we retrieve all the pending stuff. output = annotations.getPending(uid, payload) return UR.prepare_response(output)
def get_stats_ensemble(payload, req): uid = UR.getUserId(req) id_ensemble = payload["id_ensemble"] if not auth.canSeeGrades(uid, id_ensemble): return UR.prepare_response({}, 1, "NOT ALLOWED") retval = annotations.get_stats_ensemble(payload) return UR.prepare_response(retval)
def delete_file(P, req): #this method is used to rename both files and folders. uid = UR.getUserId(req) f_auth = auth.canDeleteFile if P["item_type"]=="file" else auth.canDeleteFolder if not f_auth(uid, P["id"]): return UR.prepare_response({}, 1, "NOT ALLOWED") return UR.prepare_response({"id": annotations.delete_file(uid, P)}) #special form since file isn't in there anymore
def update_ensemble(P, req): uid = UR.getUserId(req) eid = P["id_ensemble"] if uid is None or eid is None: return UR.prepare_response({}, 1, "NOT ALLOWED") ensemble = M.Ensemble.objects.get(pk=eid) if "name" in P: ensemble.name = P["name"] if "description" in P: ensemble.description = P["description"] if "allow_staffonly" in P: ensemble.allow_staffonly = P["allow_staffonly"] if "allow_anonymous" in P: ensemble.allow_anonymous = P["allow_anonymous"] if "allow_tag_private" in P: ensemble.allow_tag_private = P["allow_tag_private"] if "allow_guest" in P: ensemble.allow_guest = P["allow_guest"] if "use_invitekey" in P: ensemble.use_invitekey = P["use_invitekey"] if "allow_download" in P: ensemble.allow_download = P["allow_download"] if "allow_ondemand" in P: ensemble.allow_ondemand = P["allow_ondemand"] if "default_pause" in P: ensemble.default_pause = P["default_pause"] if "section_assignment" in P: ensemble.section_assignment = P["section_assignment"] if "metadata" in P: ensemble.metadata = P["metadata"] ensemble.save() return UR.prepare_response(annotations.get_class_settings(uid, {"id_ensemble":P["id_ensemble"]}))
def log_history(payload, req): uid = UR.getUserInfo(req, True).id if uid is None: #SACHA TODO: LOG this. return UR.prepare_response({}, 1, "NOT ALLOWED") cid = UR.CID if cid == 0: return UR.prepare_response({}, 1, "CID MOST BE NONZERO") session, previous_activity = annotations.markActivity(cid) if session is None: return UR.prepare_response({}, 1, "SESSION NOT FOUND") id_session = session.id output={} if "seen" in payload and cid != 0: annotations.markCommentSeen(uid, id_session, payload["seen"]) if "page" in payload and cid != 0: annotations.markPageSeen(uid, id_session, payload["page"]) if "idle" in payload and cid != 0: annotations.markIdle(uid, id_session, payload["idle"]) if "__return" in payload and cid != 0: R = payload["__return"] if R["type"] == "newNotesOnFile": id_source = R["a"]["id_source"] if auth.canReadFile(uid, id_source): output["locations"], output["comments"] = annotations.getCommentsByFile(id_source, uid, previous_activity) return UR.prepare_response(output)
def upload(req): r = HttpResponse() f = req.FILES["file"] id_ensemble = req.GET["id_ensemble"] id_source = req.GET["id_source"] id_folder = req.GET.get("id_folder", None) uid = UR.getUserId(req); logging.info("upload uid=%s, id_source=%s, id_ensemble=%s, id_folder=%s" % (uid,id_source,id_ensemble,id_folder)) url = "http://%s:%s/%s?id_ensemble=%s" %("localhost", "8080",f.name, id_ensemble) payload = {"url": url, "id_source": id_source, "id_folder": id_folder } if auth.canInsertFile(uid, id_ensemble, id_folder): #the followong data will be deleted in utils_pdf if an PDF error happens later... annotations.createSource(uid, payload) annotations.addOwnership(id_source, id_ensemble, id_folder) REPOSITORY_DIR = "%s/%s" % (settings.HTTPD_MEDIA, "/pdf/repository") f2 = open("%s/%s" % (REPOSITORY_DIR, id_source,),"wb") f2.write(f.read()) f2.close() basedir = dirname(dirname(abspath(__file__))) #do the rest in the background, so server remains responsive cmd = "(cd %s; python -m upload.jobs file_img %s >/tmp/uploadscript_%s.log 2>&1 &)" %(basedir, id_source, id_log ) logging.info(cmd) os.system(cmd) r.content = UR.prepare_response({}) else: r.content = UR.prepare_response({}, 1, "NOT ALLOWED to insert a file to this group") return r
def set_location_section(P, req): uid = UR.getUserId(req) if not auth.canAdministrateLocation(uid, P["id_location"]): return UR.prepare_response({}, 1, "NOT ALLOWED") result = annotations.setLocationSection(P["id_location"], P["id_section"]) locations, html5locations = annotations.getLocation(result.pk) return UR.prepare_response( locations )
def get_section_participants(payload, req): uid = UR.getUserId(req) if "id_ensemble" in payload: if auth.canGetMembers(uid, payload["id_ensemble"]): section_participants = annotations.get_section_participants(uid, payload) return UR.prepare_response(section_participants) return UR.prepare_response({}, 1, "NOT ALLOWED")
def get_class_settings(payload, req): uid = UR.getUserId(req) if "id_ensemble" in payload: if auth.canGetMembers(uid, payload["id_ensemble"]): class_settings = annotations.get_class_settings(uid, payload) return UR.prepare_response(class_settings) return UR.prepare_response({}, 1, "NOT ALLOWED")
def saveNote(payload, req): uid = UR.getUserId(req) if not auth.canAnnotate(uid, payload["id_ensemble"]): return UR.prepare_response({}, 1, "NOT ALLOWED") payload["id_author"] = uid retval = {} a = annotations.addNote(payload) if len(a) == 0: return UR.prepare_response({}, 2, "DUPLICATE") tms = {} for mark in payload["marks"]: tm = M.ThreadMark() m_types = [c[0] for c in tm.TYPES if c[1]==mark] if len(m_types): #old clients may return types we don't have in DB so ignore them tm.type = m_types[0] tm.user_id = uid tm.comment=a[0] tm.location_id=tm.comment.location_id tm.save() tms[tm.id] = UR.model2dict(tm) retval["locations"], html5 = annotations.getLocation(a[0].location_id) if (html5 is not None): retval["html5locations"]=html5 retval["comments"] = {} retval["tags"] = {} for annotation in a: retval["comments"].update(annotations.getComment(annotation.id, uid)) retval["tags"].update(annotations.getTagsByComment(annotation.id)) retval["threadmarks"] = tms return UR.prepare_response(retval)
def deleteThread(payload, req): uid = UR.getUserId(req) if not auth.canDeleteThread(uid, payload["id_location"]): return UR.prepare_response({}, 1, "NOT ALLOWED") else: annotations.deleteThread(payload) return UR.prepare_response({"id_location": payload["id_location"]})
def getHTML5Info(payload, req): if "url" not in payload: return UR.prepare_response({}, 1, "missing url !") url = payload["url"].partition("#")[0].rstrip("/") # remove hash part of the URL by default, as well as trailing slash. #TODO: use optional argument id_ensemble to disambiguate if provided. sources_info = M.HTML5Info.objects.filter(url=url) ownerships = M.Ownership.objects.select_related("source", "ensemble", "folder").filter(source__html5info__in=sources_info, deleted=False) #TODO: with django 1.9, you can use Q objects to OR two conditions #so instead of iterating to test below, just add .filter(Q(ensemble__memberships__user=UR.getUserId(req)) | Q(ensemble.allow_guest)) #then use UR.qs2dict as was done previously if not ownerships.exists(): return UR.prepare_response({}, 1, "this URL is not recognized: ") output = { "files": {}, "ensembles": {}, "folders": {} } for r in ownerships: if (r.ensemble.allow_guest or auth.isMember(UR.getUserId(req),r.ensemble_id)): output["ensembles"][r.ensemble_id]=UR.model2dict(r,annotations.__NAMES["ensembles2"]) output["files"][r.source_id]=UR.model2dict(r,annotations.__NAMES["files2"]) output["folders"][r.folder_id]=UR.model2dict(r,annotations.__NAMES["folders2"]) if (output["ensembles"]): return UR.prepare_response(output) else: return UR.prepare_response({}, 1, "not allowed: guest access isn't allowed for this file.")
def rename_file(P, req): #this method is used to rename both files and folders. uid = UR.getUserId(req) f_auth = auth.canRenameFile if P["item_type"]=="file" else auth.canRenameFolder if not f_auth(uid, P["id"]): return UR.prepare_response({}, 1, "NOT ALLOWED") return UR.prepare_response({P["item_type"]+"s": annotations.rename_file(uid, P)})
def editNote(payload, req): uid = UR.getUserId(req) if not auth.canEdit(uid, payload["id_comment"]): return UR.prepare_response({}, 1, "NOT ALLOWED") else: annotations.editNote(payload) #no need to worry about threadmarks: they can't be changed from an "edit-mode" editor return UR.prepare_response({"comments": annotations.getComment(payload["id_comment"], uid)})
def deleteNote(payload, req): uid = UR.getUserId(req) #print "trying to delete %s" %( payload["id_comment"],) if not auth.canDelete(uid, payload["id_comment"]): return UR.prepare_response({}, 1, "NOT ALLOWED") else: annotations.deleteNote(payload) return UR.prepare_response({"id_comment": payload["id_comment"] })
def add_folder(payload, req): uid = UR.getUserId(req) id_ensemble = payload["id_ensemble"] id_parent = payload["id_parent"] if not auth.canAddFolder(uid, id_ensemble, id_parent): return UR.prepare_response({}, 1, "NOT ALLOWED") id_folder = annotations.create_folder(id_ensemble, id_parent, payload["name"]) return UR.prepare_response(annotations.get_folders(uid, {"id": id_folder}))
def getGuestFileInfo(payload, req): if "id_source" not in payload: return UR.prepare_response({}, 1, "missing id_source !") id_source = payload["id_source"] output = annotations.get_guestfileinfo(id_source) for i in output["ensembles"]: if not (output["ensembles"][i]["allow_guest"] or auth.isMember(UR.getUserId(req), i)): return UR.prepare_response({}, 1, "not allowed: guest access isn't allowed for this file.") return UR.prepare_response(output)
def getMyNotes(payload, req): uid = UR.getUserId(req) if uid is None or payload.get("query") not in __AVAILABLE_STATS: return UR.prepare_response({}, 1, "NOT ALLOWED") else: output= getattr(annotations, "get_comments_"+payload.get("query"))(uid, payload) #referer = None if "referer" not in req.META else req.META["referer"] #TODO annotations.addCollageHistory(uid, referer, query) return UR.prepare_response(output)
def approveNote(payload, req): uid = UR.getUserId(req) id_comment = payload["id_comment"] if not auth.canApprove(uid,id_comment ): return UR.prepare_response({}, 1, "NOT ALLOWED") else: annotations.approveNote(uid, payload); p = {"comments":annotations.getComment(id_comment,uid) } return UR.prepare_response(p) annotations.addApproveHistory(uid, payload)
def getSectionsInfo(payload, req): uid = UR.getUserId(req) if "id_ensemble" not in payload: return UR.prepare_response({}, 1, "MISSING id_ensemble") id_ensemble = payload["id_ensemble"] if auth.canGetSectionsInfo(uid, id_ensemble): m = M.Membership.objects.filter(user__id=uid, ensemble__id=id_ensemble, deleted=False) output={"sections": UR.qs2dict(m[0].ensemble.section_set.all())}; return UR.prepare_response(output) return UR.prepare_response({}, 1, "NOT ALLOWED")
def markNote(payload, req): uid = UR.getUserId(req) id_comment = payload["id_comment"] if not auth.canMark(uid,id_comment ): return UR.prepare_response({}, 1, "NOT ALLOWED") else: annotations.markNote(uid, payload); comments = annotations.getComment(id_comment,uid) p = {"locations":annotations.getLocation(comments[int(id_comment)]["ID_location"]), "marks": annotations.getMark(uid, payload), "comments": comments} return UR.prepare_response(p)
def sendInvites(payload, req): from django.core import mail from django.core.mail import EmailMessage uid = UR.getUserId(req); id_ensemble = payload["id_ensemble"] id_section = payload.get("id_section", None) admin = 0 if "admin" not in payload else payload["admin"] if not auth.canSendInvite(uid,id_ensemble): return UR.prepare_response({}, 1, "NOT ALLOWED") #extract emails in a somewhat robust fashion (i.e. using several possible delimiters) emails = parseEntities(payload["to"], [",", "\n", " "]) #remove spurious stuff: strings that don't have an "@" and trailings "<" and ">" characters, #because some emails the following format: John Doe <*****@*****.**> emails = [o.replace("<", "").replace(">", "") for o in emails if "@" in o] logging.info("to: %s, extracted: %s" % (payload["to"], emails)) #add new users to DB w/ pending status connection = mail.get_connection() emailmessages = [] for email in emails: user = auth.user_from_email(email) password="" if user is None: ckey = "".join([ random.choice(string.ascii_letters+string.digits) for i in xrange(0,32)]) password = "".join([ random.choice(string.ascii_letters+string.digits) for i in xrange(0,4)]) user = auth.addUser(email, password, ckey) invite_key = "".join([ random.choice(string.ascii_letters+string.digits) for i in xrange(0,50)]) auth.addInvite(invite_key, user.id, id_ensemble, id_section, admin) link = "http://%s/confirm_invite?invite_key=%s" % (settings.HOSTNAME, invite_key,) ensemble = M.Ensemble.objects.get(pk=id_ensemble) p = { "name": ensemble.name, "description": ensemble.description, "link": link, "contact": user.firstname if user.firstname != None else user.email } if payload["msg"] != "": p["msg_perso"] = payload["msg"] # TODO: We still include the password in the e-mail, should we stop doing that? if password != "": p["password"] = password p["email"] = email msg = render_to_string("email/msg_invite",p) bcc = [] if settings.SMTP_CC_USER is None else (settings.SMTP_CC_USER,) e = EmailMessage("You're invited on the %s channel !" % (p["name"],), msg, settings.EMAIL_FROM, (email, ), bcc,connection=connection) emailmessages.append(e) #time.sleep(SLEEPTIME) #in order not to stress out the email server connection.send_messages(emailmessages) return UR.prepare_response({"msg": "Invite for %s sent to %s" % (ensemble.name, emails,)})
def markThread(payload, req): uid = UR.getUserId(req) id_location = payload["id_location"] if not auth.canMarkThread(uid,id_location ): return UR.prepare_response({}, 1, "NOT ALLOWED") else: mark = annotations.markThread(uid, payload); tms = {} tms[mark["id"]] = mark p = {"threadmarks": tms} return UR.prepare_response(p)
def editNote(payload, req): uid = UR.getUserId(req) if not auth.canEdit(uid, payload["id_comment"]): return UR.prepare_response({}, 1, "NOT ALLOWED") else: annotations.editNote(payload) #for mark in payload["marks"]: # annotations.markNote(uid, {"action": payload["marks"][mark], "id_comment": payload["id_comment"]}) return UR.prepare_response({"comments": annotations.getComment(payload["id_comment"], uid), "marks": annotations.getMark(uid,{"id_comment": payload["id_comment"]}) })
def getCommentLabels(payload, req): uid = UR.getUserId(req) if "file" in payload: #access by file id_source = payload["file"] o = M.Membership.objects.filter(ensemble__in=M.Ensemble.objects.filter(ownership__in=M.Ownership.objects.filter(source__id=id_source))).filter(user__id=uid, deleted=False) if len(o)>0 and o[0].admin: #for now, simply restrict to admin level output = {} lc = M.LabelCategory.objects.filter(ensemble = o[0].ensemble) output["labelcategories"] = UR.qs2dict(lc) comments = M.Comment.objects.filter(location__source__id=id_source, deleted=False, moderated=False) output["commentlabels"] = UR.qs2dict(M.CommentLabel.objects.filter(category__in=lc, comment__in=comments, grader__id=uid)) return UR.prepare_response(output) return UR.prepare_response({}, 1, "NOT ALLOWED")
def login_user(P,req): email = P["email"] if "email" in P else None password = P["password"] if "password" in P else None if email is None or password is None: return UR.prepare_response({"ckey": None}) user = auth.checkUser(email, password) if user is None: return UR.prepare_response({"ckey": None}) u_in = json.loads(urllib.unquote(req.COOKIES.get("userinfo", urllib.quote('{"ckey": ""}')))) if "ckey" in u_in and u_in["ckey"] != "" and u_in["ckey"] != user.confkey: #log that there's been an identity change auth.log_guest_login(u_in["ckey"], user.id) return UR.prepare_response({"ckey": user.confkey, "email": user.email, "firstname": user.firstname, "lastname":user.lastname, "guest": user.guest, "valid": user.valid}) #this is what's needed for the client to set a cookie and be authenticated as the new user !
def editNote(payload, req): uid = UR.getUserId(req) if not auth.canEdit(uid, payload["id_comment"]): return UR.prepare_response({}, 1, "NOT ALLOWED") else: edited_loc = annotations.editNote(payload) tags = {} tags.update(annotations.getTagsByComment(payload["id_comment"])) #no need to worry about threadmarks: they can't be changed from an "edit-mode" editor retval = {"comments": [annotations.getComment(payload["id_comment"], uid)], "tags": tags, "cid": payload["id_comment"]} if not edited_loc == None: retval["edit_location"] = edited_loc return UR.prepare_response(retval)
def upload(req): try: r = HttpResponse() f = req.FILES["file"] id_ensemble = req.GET["id_ensemble"] id_source = req.GET["id_source"] id_folder = req.GET.get("id_folder", None) uid = UR.getUserId(req) except UnreadablePostError: #most likely a canceled upload r.content = UR.prepare_response({}, 1, "unreadable post") return r except MultiValueDictKeyError: #most likely no file submitted r.content = UR.prepare_response({}, 1, "no file submitted") return r logging.info("upload uid=%s, id_source=%s, id_ensemble=%s, id_folder=%s" % (uid, id_source, id_ensemble, id_folder)) url = "http://%s:%s/%s?id_ensemble=%s" % ("localhost", "8000", f.name, id_ensemble) payload = {"url": url, "id_source": id_source, "id_folder": id_folder} if auth.canInsertFile(uid, id_ensemble, id_folder): #the followong data will be deleted in utils_pdf if an PDF error happens later... annotations.createSource(uid, payload) ownership = annotations.addOwnership(id_source, id_ensemble, id_folder) source = ownership.source #bug? before it was %s/%s which produced // REPOSITORY_DIR = "%s%s" % (settings.HTTPD_MEDIA, "/pdf/repository") print REPOSITORY_DIR f2 = open("%s/%s" % ( REPOSITORY_DIR, id_source, ), "wb") f2.write(f.read()) f2.close() if insert_pdf_metadata(id_source, REPOSITORY_DIR): V = { "reply_to": settings.SMTP_REPLY_TO, "email": source.submittedby.email, "title": source.title, "submitted": ownership.published, "protocol": settings.PROTOCOL, "hostname": settings.HOSTNAME, "id_source": id_source, "firstname": source.submittedby.firstname } msg = render_to_string("email/msg_pdfdone", V) email = EmailMessage( "The PDF file that you've submitted is now ready on NB.", msg, settings.EMAIL_FROM, (V["email"], settings.SMTP_CC_USER), (settings.EMAIL_BCC, )) email.send() else: #send email that stg didn't work and remove that document. V = { "reply_to": settings.SMTP_REPLY_TO, "email": source.submittedby.email, "source_id": id_source, "title": source.title, "submitted": ownership.published, "support": settings.SUPPORT_LINK, "contact_email": settings.NBTEAM_EMAIL, "firstname": source.submittedby.firstname } ownership.delete() source.delete() msg = render_to_string("email/msg_pdferror", V) email = EmailMessage( "NB was unable to read a PDF file that you've submitted", msg, settings.EMAIL_FROM, (V["email"], settings.SMTP_CC_PDFERROR), (settings.EMAIL_BCC, )) email.send() r.content = UR.prepare_response({}) else: r.content = UR.prepare_response( {}, 1, "NOT ALLOWED to insert a file to this group") return r
def subscribe_with_key(req): key = req.GET.get("key", "") if not key: return HttpResponse(UR.prepare_response({}, 1, "NOT ALLOWED")) try: e = M.Ensemble.objects.get(invitekey=key) except ObjectDoesNotExist: return HttpResponse(UR.prepare_response({}, 1, "NOT ALLOWED")) if not e.use_invitekey: return HttpResponse(UR.prepare_response({}, 1, "NOT ALLOWED")) auth_user = UR.getUserInfo(req) if req.method == 'GET': if auth_user is None: # Guest retrieving the subscribe page remote_form = RemoteForm(forms.UserForm()) return HttpResponse( UR.prepare_response({ "new_user": True, "class_settings": UR.model2dict(e), "form": remote_form.as_dict() })) else: # Logged in user retrieving the subscribe page user = auth_user remote_form = RemoteForm(forms.UserForm(instance=user)) m = M.Membership.objects.filter(user=user, ensemble=e) if m.count() == 0: m = M.Membership(user=user, ensemble=e) m.save() return HttpResponse( UR.prepare_response({ "new_user": False, "user": UR.model2dict(user), "class_settings": UR.model2dict(e), "form": remote_form.as_dict() })) else: # POST requests if auth_user is None: # Guest subscribing to a class user = M.User(confkey="".join([ choice(string.ascii_letters + string.digits) for i in xrange(0, 32) ])) req.POST = dict(req.POST.iteritems() ) # Convert immutable object to mutable object user_form = forms.UserForm(req.POST, instance=user) if user_form.is_valid(): user_form.save() m = M.Membership(user=user, ensemble=e) m.save( ) # membership exists but user is still invalid until has confirmed their email p = { "tutorial_url": settings.GUEST_TUTORIAL_URL, "conf_url": "%s://%s/?ckey=%s" % (settings.PROTOCOL, settings.NB_SERVERNAME, user.confkey), "firstname": user.firstname, "email": user.email } email = EmailMessage( "Welcome to NB, %s" % (user.firstname, ), render_to_string("email/confirm_subscribe", p), settings.EMAIL_FROM, (user.email, ), (settings.EMAIL_BCC, )) email.send() return HttpResponse( UR.prepare_response({ "new_user": True, "class_settings": UR.model2dict(e), "next": "/subscribe_thanks" })) else: # Invalid form - return form with error messages __clean_form( user_form ) # Ensure user-generated data gets cleaned before sending back the form remote_form = RemoteForm(user_form) return HttpResponse( UR.prepare_response({ "new_user": True, "user": UR.model2dict(user), "class_settings": UR.model2dict(e), "form": remote_form.as_dict() })) else: # Logged in user subscribing to a class user = auth_user m = M.Membership.objects.filter(user=user, ensemble=e) if m.count() == 0: m = M.Membership(user=user, ensemble=e) m.save() return HttpResponse( UR.prepare_response({ "new_user": False, "class_settings": UR.model2dict(e), "next": "/" }))
def getStats2(payload, req): uid = UR.getUserId(req) if uid is None: return UR.prepare_response({}, 1, "NOT ALLOWED") else: return UR.prepare_response(annotations.get_stats2(uid))
def get_top_comments_from_locations(P, req): retval = {} retval["comments"] = annotations.getTopCommentsFromLocations( P["id_locations"]) return UR.prepare_response(retval)
def advanced_filter(P, req): retval = {} retval["locs"] = annotations.getAdvancedFilteredLocationsByFile( P["id_source"], P["n"], P["r"], P["type"]) return UR.prepare_response(retval)
def request_source_id(payload, req): uid = UR.getUserId(req) if uid is None: return UR.prepare_response({}, 1, "NOT ALLOWED") logging.info("[request_source_id]: %s" % (payload, )) return UR.prepare_response({"id_source": annotations.createSourceID()})
def move_file(P,req): uid = UR.getUserId(req) f_auth = auth.canMoveFile if P["item_type"]=="file" else auth.canMoveFolder if not f_auth(uid, P["id"], P["dest"]): return UR.prepare_response({}, 1, "NOT ALLOWED") return UR.prepare_response({P["item_type"]+"s": annotations.move_file(uid, P)})
def getGradees(payload, req): uid = UR.getUserId(req) output = {"gradees": annotations.getGradees(uid)} return UR.prepare_response(output)
def newsite_form(req): import base.models as M, random, string auth_user = UR.getUserInfo(req) if auth_user is not None: return HttpResponse(UR.prepare_response({"redirect": "/"})) if req.method == 'GET': remote_user_form = RemoteForm(forms.UserForm()) remote_class_form = RemoteForm(forms.EnsembleForm()) return HttpResponse( UR.prepare_response({ "user_form": remote_user_form.as_dict(), "class_form": remote_class_form.as_dict() })) else: user = M.User(confkey="".join([ choice(string.ascii_letters + string.digits) for i in xrange(0, 32) ])) ensemble = M.Ensemble() req.POST = dict( req.POST.iteritems()) # Convert immutable object to mutable object user_form = forms.UserForm(req.POST, instance=user) ensemble_form = forms.EnsembleForm(req.POST, instance=ensemble) if user_form.is_valid() and ensemble_form.is_valid(): user_form.save() ensemble.invitekey = "".join([ random.choice(string.ascii_letters + string.digits) for i in xrange(0, 50) ]) ensemble_form.save() m = M.Membership(user=user, ensemble=ensemble, admin=True) m.save() p = { "tutorial_url": settings.GUEST_TUTORIAL_URL, "conf_url": "http://%s?ckey=%s" % (settings.NB_SERVERNAME, user.confkey), "firstname": user.firstname, "email": user.email } email = EmailMessage("Welcome to NB, %s" % (user.firstname), render_to_string("email/confirm_newsite", p), settings.EMAIL_FROM, (user.email, ), (settings.EMAIL_BCC, )) email.send() return HttpResponse( UR.prepare_response({"redirect": "/newsite_thanks"})) else: # Invalid form - return form with error messages __clean_form( user_form ) # Ensure user-generated data gets cleaned before sending back the form __clean_form( ensemble_form ) # Ensure user-generated data gets cleaned before sending back the form remote_user_form = RemoteForm(user_form) remote_class_form = RemoteForm(ensemble_form) return HttpResponse( UR.prepare_response({ "user_form": remote_user_form.as_dict(), "class_form": remote_class_form.as_dict() }))
def sendInvites(payload, req): from django.core import mail from django.core.mail import EmailMessage uid = UR.getUserId(req) id_ensemble = payload["id_ensemble"] id_section = payload.get("id_section", None) admin = 0 if "admin" not in payload else payload["admin"] if not auth.canSendInvite(uid, id_ensemble): return UR.prepare_response({}, 1, "NOT ALLOWED") #extract emails in a somewhat robust fashion (i.e. using several possible delimiters) emails = parseEntities(payload["to"], [",", "\n", " "]) #remove spurious stuff: strings that don't have an "@" and trailings "<" and ">" characters, #because some emails the following format: John Doe <*****@*****.**> emails = [o.replace("<", "").replace(">", "") for o in emails if "@" in o] logging.info("to: %s, extracted: %s" % (payload["to"], emails)) #add new users to DB w/ pending status connection = mail.get_connection() emailmessages = [] for email in emails: user = auth.user_from_email(email) password = "" if user is None: ckey = "".join([ random.choice(string.ascii_letters + string.digits) for i in xrange(0, 32) ]) password = "".join([ random.choice(string.ascii_letters + string.digits) for i in xrange(0, 4) ]) user = auth.addUser(email, password, ckey) invite_key = "".join([ random.choice(string.ascii_letters + string.digits) for i in xrange(0, 50) ]) auth.addInvite(invite_key, user.id, id_ensemble, id_section, admin) link = "http://%s/confirm_invite?invite_key=%s" % ( settings.HOSTNAME, invite_key, ) ensemble = M.Ensemble.objects.get(pk=id_ensemble) p = { "name": ensemble.name, "description": ensemble.description, "link": link, "contact": user.firstname if user.firstname != None else user.email } if payload["msg"] != "": p["msg_perso"] = payload["msg"] # TODO: We still include the password in the e-mail, should we stop doing that? if password != "": p["password"] = password p["email"] = email msg = render_to_string("email/msg_invite", p) bcc = [] if settings.SMTP_CC_USER is None else ( settings.SMTP_CC_USER, ) e = EmailMessage("You're invited on the %s channel !" % (p["name"], ), msg, settings.EMAIL_FROM, (email, ), bcc, connection=connection) emailmessages.append(e) #time.sleep(SLEEPTIME) #in order not to stress out the email server connection.send_messages(emailmessages) return UR.prepare_response( {"msg": "Invite for %s sent to %s" % ( ensemble.name, emails, )})
def editPoll(payload, req): uid = UR.getUserId(req) if uid is None or ("id_poll" not in payload) or not annotations.canEditPoll(uid, payload["id_poll"]): return UR.prepare_response({}, 1, "NOT ALLOWED") annotations.editPoll(uid, payload) return UR.prepare_response({})
def getPending(payload, req): uid = UR.getUserId(req) output = annotations.getPending(uid, payload) return UR.prepare_response(output)
def bulk_import_annotations(P, req): uid = UR.getUserId(req) if not auth.canImportAnnotation(uid, P["from_source_id"], P["to_source_id"]): return UR.prepare_response({}, 1, "NOT ALLOWED") return UR.prepare_response( annotations.bulkImportAnnotations(P["from_source_id"], P["to_source_id"], P["locs_array"], P["import_type"]))
def getMembers(payload, req): uid = UR.getUserId(req) if "id_ensemble" in payload: if auth.canGetMembers(uid, payload["id_ensemble"]): return UR.prepare_response(annotations.get_members(payload["id_ensemble"])) return UR.prepare_response({}, 1, "NOT ALLOWED")
def delete_file(P, req): uid = UR.getUserId(req) if not auth.canDeleteFile(uid, P["id"]): return UR.prepare_response({}, 1, "NOT ALLOWED") return UR.prepare_response({"id": annotations.delete_file( uid, P)}) #special form since file isn't in there anymore
def save_settings(payload, req): uid = UR.getUserId(req); if uid is None: return UR.prepare_response({}, 1, "NOT ALLOWED") else: return UR.prepare_response({"settings": annotations.save_settings(uid, payload)})
def add_ensemble(payload, req): uid = UR.getUserId(req) if uid is None: return UR.prepare_response({}, 1, "NOT ALLOWED") id = annotations.create_ensemble(uid, payload) return UR.prepare_response(annotations.get_ensembles(uid, {"id": id}))
def move_file(P, req): uid = UR.getUserId(req) if not auth.canMoveFile(uid, P["id"]): return UR.prepare_response({}, 1, "NOT ALLOWED") return UR.prepare_response({"files": annotations.move_file(uid, P)})
def edit_assignment(P, req): uid = UR.getUserId(req) if not auth.canEditAssignment(uid, P["id"]): return UR.prepare_response({}, 1, "NOT ALLOWED") return UR.prepare_response({"files": annotations.edit_assignment(uid, P)})
def getParams(payload, req): o = {} for p in payload["name"]: if p in __AVAILABLE_PARAMS: o[p] = constants.__dict__[p] return UR.prepare_response({"value": o})