def groupByMessage(als:Iterable[models.Alert]) \ -> Iterable[Tuple[models.Message,List[str]]]: """ Group the alerts by message. For each group of alerts with a messages, return that message and the userIds of the users who starred it. """ mid: str = "" # message id m = None # message of (mid) users: List[str] = [] dpr("mid=%r users=%r", mid, users) for al in als: newMid = al.message_id if newMid != mid: dpr("mid=%r newMid=%r", mid, newMid) if mid != "": dpr("yielding (%r, %r)", mid, users) yield (m, users) mid = newMid m = models.Message.getDoc(mid) users = [] users += [al.doer_id] dpr("mid=%r users=%r", mid, users) #//for al if mid != "": dpr("yielding (%r, %r)", mid, users) yield (m, users)
def user(id): if id=='NEW': doc = userdb.User() dpr("doc=%r", doc) else: doc = userdb.User.getDoc(id) dpr("doc=%r", doc) msg = "" if request.method=='POST': doc = doc.populateFromRequest(request) if doc.isValid(): if request.form['delete']=="1": doc.delete() msg = "Deleted user" else: doc.save() msg = "Saved user" #//if tem = jinjaEnv.get_template("user.html") h = tem.render( doc = doc, id = htmlEsc(id), msg = ht.goodMessageBox(msg), ) return h #--------------------------------------------------------------------- #end
def xFollow(id: str, status: str): """ @param id = the followee user who the currently-logged-in user is following or unfollowing @param status = following status, 0=unfollow, 1=follow """ makeFollowing = (status == "1") cun = currentUserName() dpr("id=%r status=%r cun=%r", id, status, cun) if not cun: return "{}" cu = User.getDoc(cun) if not cu: return "{}" followee = User.getDoc(id) if not followee: return "{}" ai = models.getAccountInfo(cun) followingSet = set(ai.following_ids) if makeFollowing: followingSet2 = followingSet | set([id]) else: followingSet2 = followingSet - set([id]) if followingSet2 != followingSet: ai.following_ids = list(followingSet2) ai.save() return "{}"
def adq(qtext: str, id: str = ""): global qList if id: dpr("id=%r", id) id = questionManager.getCurrentGroupId() + "-" + id dpr("id=%r", id) q = AgreeDisagreeQuestion(id, qtext) questionManager.addQuestion(q)
def wiki_page(u, pathName): dpr("pathName=%r", pathName) folder, filename = decomposePathName(pathName) dpr("folder=%r filename=%r", folder, filename) if filename == "": return wikiDir(u, folder) else: return wikiPage(u, folder, filename)
def mcq(qtext: str, answers: MultiChoiceAnswers, id: str = ""): global qList if id: dpr("id=%r", id) id = questionManager.getCurrentGroupId() + "-" + id dpr("id=%r", id) q = MultiChoiceQuestion(id, qtext, answers) questionManager.addQuestion(q)
def hashPassword(password: str) -> str: encrypted = pyscrypt.hash(password=toBytes(password), salt=toBytes("salt"), N=128, r=1, p=1, dkLen=256) dpr("encrypted=%r:%s", encrypted, type(encrypted)) hx = toHex(encrypted) dpr("hx=%r:%s", hx, type(hx)) return hx
def askq(): dpr("in askq()") if request.method == 'POST': pass #//if tem = jinjaEnv.get_template("askq.html") h = tem.render( qs=questlib.questionListH() # get html-formatted list of questions ) return h
def calcGroupTable(userName: str) -> str: """ caslculate the group table for the current user. Returns html. """ h = """<table class='bz-report-table'> <tr> <th>Group</th> <th>Questions<br>Answered</th> <th>Questions<br>Unanswered</th> <th>Details</th> </tr> """ groups = questionManager.getGroups() for group in groups: dpr("group.id=%r", group.id) numQs = len(group.questions) numAnswered = len(answeredQs(currentUserName(), group.questions)) numUnanswered = numQs - numAnswered if numUnanswered == 0: detailsH = form( "View <a href='/results/{groupId}' class='green'>" "<i class='fa fa-star'></i> " "Your Results</a>", groupId=htmlEsc(group.id)) else: detailsH = ("<i class='fa fa-lock'></i> " "<i>answer all questions to unlock details</i>") h += form( """ <tr> <td><a href="/group/{groupId}">{groupName}</a></td> <td style='text-align:right;'> <a href="/answered/{groupId}">{numAnswered}</a></td> <td style='text-align:right;'> <a href="/ask/{groupId}">{numUnanswered}</a>/{numTotal}</td> <td>{details}</td> </tr> """, groupId=htmlEsc(group.id), numQs=numQs, groupName=htmlEsc(group.title), numAnswered=numAnswered, numUnanswered=numUnanswered, numTotal=numQs, details=detailsH, ) #//for h += "</table>\n" return h
def pollChartData() -> dict: """ return data for poll chart, in format for Flot charting application """ # polls, sorted earliest first allPolls = sorted(Poll.polls, key=lambda po: po.dateInt) j = [] partyStrengths = [] for p, xAdj in zip(POLL_PARTIES, PARTY_X_ADJ): pa = party.Party.docs[p] xySeries = [] dataForTrend = [] trendSeries = [] for po in allPolls: xySeries.append([po.dateInt+xAdj, po.__dict__[p]]) dataForTrend.append( (po.dateInt, po.sample, po.__dict__[p])) trendSeries.append([po.dateInt, calcTrend(dataForTrend)]) #//for po series = { 'label': p, 'color': pa.col, 'data': xySeries, 'points': {'show': True} } trendSeries = { 'color': pa.col, 'data': removeDuplicateDates(trendSeries), 'lines': {'show': True, 'lineWidth': 2} } j.append(series) j.append(trendSeries) j.append({ 'data': [[0,0]], #'points': {'show': True} }) partyStrengths.append({ 'name': pa.getNameH(), 'color': pa.col, 'strength': trendSeries['data'][-1][1] }) #//for pa j.append({ 'data': [[0,0]], #'points': {'show': True} }) dpr("partyStrengths=%r", partyStrengths) return j, partyStrengths
def blog(id): user = User.getDoc(id) ai = models.getAccountInfo(id) lf = BlogFormatter(id) numPosts = models.Message.count({'author_id': id}) numHeadPosts = models.Message.count({ 'author_id': id, 'replyTo_id': { '$in': [None, ''] }, }) numFollowing = len(ai.following_ids) numFollowers = models.AccountInfo.count({'following_ids': id}) cun = currentUserName() if not cun: # not logged in, so no follow button followButton = "" else: if models.follows(cun, id): # follows, so unfollow button followButton = "unfollow" else: # doesn't currently follow, so follow button followButton = "follow" dpr("followButton=%r", followButton) tem = jinjaEnv.get_template("blog.html") h = tem.render( id=id, idJson=json.dumps(id), user=user, ai=ai, blogTitle=ai.asReadableH('title'), name=ai.asReadableH('realName'), bio=ai.bioHtml, numPosts=numPosts, numHeadPosts=numHeadPosts, numFollowing=numFollowing, numFollowers=numFollowers, followButton=followButton, lf=lf, ) return h
def login(): tem = jinjaEnv.get_template("login.html") doc = LoginForm() msg = "" if request.method=='POST': #>>>>> CSRF handling dpr("@@@ session=%r @@@", session) token = session.pop('_csrf_token', None) dpr("@@@ token=%r @@@", token) #if not token or token != request.form.get('_csrf_token'): # pass # #abort(403) doc = doc.populateFromRequest(request) u = userdb.User.find_one({'userName': doc.userName}) ok = u and userdb.verifyPassword(u.hashedPassword, doc.password) dpr("doc.password=%r ok=%r", doc.password, ok) if ok: login_user(u) return redirect("/", code=302) else: msg = "login failed" h = tem.render( doc = doc, msg = ht.errorBox(msg), ) return h
def ask(groupId, numQs=DEFAULT_NUM_QS): numQs = butil.exValue(lambda: int(numQs), DEFAULT_NUM_QS) dpr("groupId=%r, numQs=%r", groupId, numQs) group = questionManager.getGroup(groupId) if not group: return http403("Group does not exist") cun = currentUserName() if request.method == 'POST': rf = dict(request.form) dpr("request form data: rf=%r", rf) # in (rf) keys are question ids, values are question values. # if the user hasn't answered a question, it is missing from the # dictionary for qid, ansVal in rf.items(): q = getQ(group.questions, qid) if q: models.saveAnswer(cun, q.qid, ansVal) #//for #//if unansweredQs = getUnansweredQs(group, cun) qsToAsk = unansweredQs[:numQs] qListH = getQuestionsH(qsToAsk) numAns = len(group.questions) - len(unansweredQs) tem = jinjaEnv.get_template("ask.html") h = tem.render( group=group, groupTitle=htmlEsc(group.title), groupId=htmlEsc(group.id), numQ=len(group.questions), # questions in this group numAns=numAns, # q's answered numUnanswered=len(unansweredQs), # q's unanswered numAsk=len(qsToAsk), # q's to ask on this page qs=qListH, ) return h
def accountSettings(): cun = currentUserName() dpr("id=%r cun=%r", id, cun) #if id != cun: # return http403() user = User.getDoc(cun) ai = models.getAccountInfo(cun) msg = "" if request.method=='POST': ai = ai.populateFromRequest(request) ai.save() msg = "Saved account settings" #//if tem = jinjaEnv.get_template("accountSettings.html") h = tem.render( user = user, ai = ai, msg = ht.goodMessageBox(msg), ) return h
def substFun(self, mo) -> str: """ Substitution function """ dpr("substFun() mo.groups()=%r start=%r end=%r", mo.groups(), mo.start(), mo.end()) matchedText = mo.string[mo.start():mo.end()] if matchedText[:2] == "[#": hashtag = matchedText[2:-1] else: hashtag = matchedText[1:] dpr("matchedText=%r hashtag=%r", matchedText, hashtag) canonicalTag = hashtag.lower().replace("-", "_").replace(" ", "_") dpr("canonicalTag=%r", canonicalTag) self.tagSet.add(canonicalTag) dpr("self.tagSet=%r", self.tagSet) result = "<a class='tag' href='/tag/%s'>#%s</a>" % (canonicalTag, hashtag) return result
def verifyPassword(hashedPassword, guessedPassword): encrypted = pyscrypt.hash(password=toBytes(guessedPassword), salt=toBytes("salt"), N=128, r=1, p=1, dkLen=256) dpr("encrypted=%r:%s", encrypted, type(encrypted)) hx = toHex(encrypted) dpr("hx=%r:%s", hx, type(hx)) ok = (hx == hashedPassword) dpr("hashedPassword=%r ok=%r", hashedPassword, ok) return ok
def getArticles(): articleFns = butil.getFilenames(ARTICLE_DIR, "*.md") dpr("ARTICLE_DIR=%r", ARTICLE_DIR) dpr("articleFns=%r", articleFns) h = "" for afn in articleFns: title = getTitle(butil.join(ARTICLE_DIR, afn)) dpr("afn=%r title=%r", afn, title) h += form( "<p><a href='/article/{art}'>" "<i class='fa fa-file-text-o'></i> {title}</a></p>\n", art=afn[:-3], title=title) #//for return h
def getStarredMessages(q: dict) -> str: """ get starred messages corresponsing to query (q). Include who starred each message """ h = "" als = models.Alert.find(q, sort=[('message_id', -1), ('created', -1)]) starrersByMessage = groupByMessage(als) for mess, starrers in starrersByMessage: dpr("starrers=%r", starrers) starrersH = ", ".join( form("<a href='/blog/{u}'>@{u}</a>", u=u) for u in starrers) dpr("starrersH=%r", starrersH) h += form("<p><br>Starred by {starrers}:</p>\n{m}\n", starrers=starrersH, m=mess.viewH()) dpr("h=%r", h) #//for al return h
def render(s: str, wikiExt: bool = False) -> Tuple[str, List[str]]: """ Render markup into HTML, also return tags @param wiki = True if it should be rendered with the WikiLinkExtension @return (h,tags) where: h:str = rendered html tags:List[str] = canonicalised hashtags """ s2 = encloseHashtagAtStart(s) s3, tags = GetHashtags(s2).calc() dpr("s3=%s", s3) if wikiExt: markdownWikiProcessor.reset() h = markdownWikiProcessor.convert(s3) else: markdownProcessor.reset() h = markdownProcessor.convert(s3) dpr("h=%s", h) h2 = sanitize(h) dpr("h2=%s", h2) return (h2, tags)
def testForm(): dpr("- - - in testForm() - - -") theTF = TheTestForm() theTF.dateOfBirth = BzDate.today() dpr("theTF=%r", theTF) resultTable = "" dpr("request=%r", request) if request.method == 'POST': theTF = theTF.populateFromRequest(request) theTF.copyOfAaa = theTF.aaa if theTF.isValid(): resultTable = getResultTable(theTF) #//if tem = jinjaEnv.get_template("testForm.html") h = tem.render( theTF=theTF, resultTable=resultTable, ) return h
def getPartyLegend(partyStrengths) -> str: """ return HTML to go at the top of the chart showing parties, in order of their trend strength, with percentage and color. """ # sort, largest 1st ps2 = sorted(partyStrengths, key=lambda ps: ps['strength'])[::-1] dpr("ps2=%r", ps2) h = "" for ps in ps2: dpr("ps=%r", ps) name = ps['name'] color = ps['color'] strength = ps['strength'] h += form("""<span style='color:{color}'> {strength:.1f}% {name}</span> """, color = color, strength = strength, name = name) #//for dpr("h=%s", h) return h
def au_messList(): lf = MessListFormatter() ts = lf.mostRecentTimeStamp() tsj = json.dumps({'ts': ts}) dpr("ts=%r tsj=%r", ts, tsj) return tsj
def messRep(id=None): if id: isReply = True m = models.Message.getDoc(id) mh = m.viewH() else: isReply = False m = None mh = "" hasPreview = False previewH = "" tags = None mf = MessageForm() if request.method == 'POST': mf = mf.populateFromRequest(request) messRepButton = request.form['messRepButton'] dpr("messRepButton=%r", messRepButton) if mf.isValid(): if messRepButton == 'preview': #>>>>> preview message previewH, tags = mark.render(mf.message) hasPreview = True else: #>>>>> create message dpr("create new message") previewH, tags = mark.render(mf.message) newM = models.Message(source=mf.message, html=previewH, tags=tags, author_id=permission.currentUserName()) if isReply: newM.replyTo_id = id newM.save() models.notifyTags(tags) dpr("newM=%r", newM) dpr("tags=%r", tags) u = "/mess/" + newM.id() dpr("u=%r", u) if isReply: al = models.Alert(user_id=m.author_id, alertType='reply', message_id=m._id, doer_id=newM.author_id, reply_id=newM._id) al.save() return redirect(u, code=303) #//if valid #//if POST tem = jinjaEnv.get_template("messRep.html") h = tem.render(id=id, isReply=isReply, m=m, mh=mh, mf=mf, msg="", hasPreview=hasPreview, previewH=previewH, tagsH=htmlEsc(repr(tags))) return h
def au_tag(t): lf = TagFormatter(t) ts = lf.mostRecentTimeStamp() tsj = json.dumps({'ts':ts}) dpr("ts=%r tsj=%r", ts, tsj) return tsj
def preSave(self): self.lastSaved = BzDateTime.now() d = self.mongoDict() d.pop('anything', "") # remove the anything field dpr("d=%r", d) self.anything = d