def main(args, opts): jdb.reset_encoding(sys.stdout, 'utf-8') errs = [] chklist = {} try: form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform() except Exception as e: jmcgi.err_page([str(e)]) fv = form.getfirst fl = form.getlist if not sess or sess.priv != 'A': users = [] else: sql = "SELECT * FROM users ORDER BY userid" sesscur = jdb.dbOpenSvc(cfg, svc, session=True, nokw=True) users = jdb.dbread(sesscur, sql) L('cgi.users').debug('read %d rows from table "user"' % (len(users), )) jmcgi.jinja_page("users.jinja", users=users, session=sess, cfg=cfg, parms=parms, svc=svc, dbg=dbg, sid=sid, this_page='user.py', result=fv('result'))
def main(args, opts): jdb.reset_encoding(sys.stdout, 'utf-8') errs = [] try: form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform() except Exception as e: jmcgi.err_page([str(e)]) # The filesystem path of the directory containing editdata files. filesdir = cfg['web']['EDITDATA_DIR'] # The URL for the directory containing editdata files. httpdir = cfg['web']['EDITDATA_URL'] fv = lambda x: (form.getfirst(x) or '').decode(Enc) is_editor = jmcgi.is_editor(sess) allfiles = sorted(os.listdir(filesdir)) editfiles = [x for x in allfiles if re.search(r'[0-9]{5}\.dat$', x)] logfiles = [x for x in allfiles if re.search(r'((ok)|(bad))\.log$', x)] jmcgi.jinja_page('jbedits.jinja', parms=parms, filesdir=filesdir, httpdir=httpdir, editfiles=editfiles, logfiles=logfiles, svc=svc, dbg=dbg, sid=sid, session=sess, cfg=cfg, this_page='jbedits.py')
def main (args, opts): jdb.reset_encoding (sys.stdout, 'utf-8') errs = [] try: form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform() except Exception as e: jmcgi.err_page ([str (e)]) # The filesystem path of the directory containing editdata files. filesdir = cfg['web']['EDITDATA_DIR'] # The URL for the directory containing editdata files. httpdir = cfg['web']['EDITDATA_URL'] fv = lambda x:(form.getfirst(x) or '').decode(Enc) is_editor = jmcgi.is_editor (sess) srcs = sorted (jdb.KW.recs('SRC'), key=lambda x: x.kw.lower()) # Get the filename url parameter, and validate it. fn = fv ('fn') if not re.search (r'[0-9]{5}\.dat$', fn) or '/' in fn: err_page (["Bad 'fn' url parameter"]) fullname = os.path.join (filesdir, fn) # Open the file, get the data. try: e, ref, comment, name, email = read_editdata (cur, fullname) except Exception as e: err_page (["Bad file data, unable to unserialize: %s" % str(e)]) extra = {'ref':ref, 'comment':comment, 'name':name, 'email':email} e.NOCORPOPT = '' # This seems to be required by template, see edform.py jmcgi.jinja_page ('edform.jinja', parms=parms, entrs=[e], extra=extra, srcs=srcs, is_editor=is_editor, svc=svc, dbg=dbg, sid=sid, session=sess, cfg=cfg, this_page='jbedit.py')
def main(args, opts): jdb.reset_encoding(sys.stdout, 'utf-8') errs = [] try: form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform() except Exception as e: jmcgi.err_page([str(e)]) fv = form.getfirst fl = form.getlist orderby = "k.id,s.kw,e.src" sql = "SELECT k.id, k.kw, k.descr, s.kw AS corpus, count(*) AS cnt " \ "FROM kwgrp k " \ "LEFT JOIN grp g ON g.kw=k.id " \ "LEFT JOIN entr e ON e.id=g.entr " \ "LEFT JOIN kwsrc s ON s.id=e.src " \ "GROUP BY k.id, k.kw, k.descr, e.src, s.kw " \ "ORDER BY %s" % orderby rs = jdb.dbread(cur, sql) jmcgi.jinja_page("groups.jinja", results=rs, parms=parms, svc=svc, dbg=dbg, sid=sid, session=sess, cfg=cfg, this_page='goups.py')
def main(args, opts): jdb.reset_encoding(sys.stdout, 'utf-8') try: form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform() except Exception as e: jmcgi.err_page([str(e)]) formvalues = form, svc, dbg, cur, sid, sess, parms, cfg fv = form.getfirst fl = form.getlist t = datetime.date.today() # Will supply default value of y, m, d. # y, m, and d below are used to construct sql string and *must* # be forced to int()'s to eliminate possibiliy of sql injection. try: y = int(fv('y') or t.year) except Exception as e: jmcgi.err_page("Bad 'y' url parameter.") return show_index = bool(fv('i')) if show_index: render_year_index(y, formvalues) else: try: m = int(fv('m') or t.month) d = int(fv('d') or t.day) n = int(fv('n') or 0) except Exception as e: jmcgi.err_page("Bad 'm', 'd' or 'n' url parameter.") return render_day_updates(y, m, d, n, formvalues)
def main(args, opts): jdb.reset_encoding(sys.stdout, 'utf-8') try: form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform() except Exception as e: jmcgi.err_page([str(e)]) jmcgi.jinja_page("edhelpq.jinja", cfg=cfg, svc=svc, dbg=dbg)
def main(args, opts): jdb.reset_encoding(sys.stdout, 'utf-8') try: form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform() except Exception as e: jmcgi.err_page([str(e)]) qs = jmcgi.form2qs(form) # reshapes()'s last argument is the maximum number of checkboxes # to put on a line, and is ajusted empirically to make the total # widths for all the sections approximately equal. pos = reshape(sorted(jdb.KW.recs('POS'), key=lambda x: x.kw.lower()), 10) misc = reshape(sorted(jdb.KW.recs('MISC'), key=lambda x: x.kw.lower()), 8) stat = reshape(sorted(jdb.KW.recs('STAT'), key=lambda x: x.kw.lower()), 10) fld = reshape(sorted(jdb.KW.recs('FLD'), key=lambda x: x.kw.lower()), 10) dial = reshape(sorted(jdb.KW.recs('DIAL'), key=lambda x: x.kw.lower()), 12) kinf = reshape(sorted(jdb.KW.recs('KINF'), key=lambda x: x.kw.lower()), 5) # FIXME: restricting 'rinf' kwds to values less that 100 causes # the searchj form not to show the the kanjidic-related ones. # This is really too hackish. See IS-190 for fix. rinf = reshape( sorted([x for x in jdb.KW.recs('RINF') if x.id < 100], key=lambda x: x.kw.lower()), 5) # FIXME: Filter out the kanjidic corpus for now. Will figure # out how to integrate it later. This too is pre- IS-190 hack. corp = reshape( sorted([x for x in jdb.KW.recs('SRC') if x.kw != 'xxkanjidic'], key=lambda x: x.kw.lower()), 10) freq = [] for x in sorted(jdb.KW.recs('FREQ'), key=lambda x: x.kw.lower()): # Build list of Kwfreq keywords for populating the webpage Freq # checkboxes. Since the 'kwfreq' table does not include the # values (the "1", "2", in "ichi1" etc), we create the expanded # values here. We also supply the "descr" value which will provide # tool tips on web page. if x.kw != 'nf' and x.kw != 'gA': freq.extend( [Kwfreq(x.kw + '1', x.descr), Kwfreq(x.kw + '2', x.descr)]) jmcgi.jinja_page("srchform.jinja", KW=jdb.KW, pos=pos, misc=misc, stat=stat, src=corp, freq=freq, fld=fld, kinf=kinf, rinf=rinf, dial=dial, parms=parms, svc=svc, dbg=dbg, sid=sid, session=sess, cfg=cfg, this_page='srchform.py')
def main( args, opts ): jdb.reset_encoding (sys.stdout, 'utf-8') try: form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform() except Exception as e: jmcgi.err_page ([str (e)]) qs = jmcgi.form2qs (form) corp = reshape (sorted (jdb.KW.recs('SRC'), key=lambda x:x.kw.lower()), 10) jmcgi.jinja_page ("srchformq.jinja", src=corp, parms=parms, svc=svc, dbg=dbg, sid=sid, session=sess, cfg=cfg, this_page='srchformq.py')
def main(args, opts): jdb.reset_encoding(sys.stdout, 'utf-8') try: form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform() except Exception as e: jmcgi.err_page([str(e)]) kwhash = {} for t in 'RINF KINF FREQ MISC POS FLD DIAL GINF SRC STAT XREF'.split(): kw = jdb.KW.recs(t) kwset = [t.capitalize(), sorted(kw, key=lambda x: x.kw.lower())] kwhash[t] = kwset[1] kwhash['LANG'] = get_langs(cur) jmcgi.jinja_page("edhelp.jinja", svc=svc, dbg=dbg, cfg=cfg, kwhash=kwhash)
def main(args, opts): jdb.reset_encoding(sys.stdout, 'utf-8') errs = [] try: form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform() except Exception as e: jmcgi.err_page([str(e)]) entries = jmcgi.get_entrs(cur, form.getlist('e'), form.getlist('q'), errs) if not entries: jmcgi.err_page("No entries found") return ids = [e.id for e in entries] sql, args = "SELECT * FROM vinflxt WHERE id IN %s", (tuple(ids), ) results = jdb.dbread(cur, sql, args) poses = set([p.kw for e in entries for s in e._sens for p in s._pos]) poskws = sorted([jdb.KW.POS[p].kw for p in poses]) if not results: if poskws: msg = "Unable to conjugate any of the following parts-of-speech: %s." % ( ', '.join(poskws)) else: msg = "Word does not have a part-of-speech tag." jmcgi.err_page(msg) return sql, args = "SELECT DISTINCT id,txt FROM vconotes WHERE pos IN %s ORDER BY id", ( tuple(poses), ) notes = jdb.dbread(cur, sql, args) cur.close() # Make notes links, replace '\n's with <br/>s. htmlify_conjs(results) # Divide the conjugations table up into sections, one for each word (by id). sections = partition_conjs(results) # Make each note a link target. htmlify_notes(notes) if errs: jmcgi.err_page(errs) jmcgi.jinja_page('conj.jinja', sections=sections, notes=notes, svc=svc, dbg=dbg, sid=sid, session=sess, cfg=cfg, parms=parms, this_page='conj.py')
def main(args, opts): jdb.reset_encoding(sys.stdout, 'utf-8') errs = [] chklist = {} try: form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform() except Exception as e: jmcgi.err_page([str(e)]) fv = form.getfirst fl = form.getlist L('cgi.user').debug("sess=%r" % sess) L('cgi.user').debug("u=%r, new=%r" % (fv('u'), fv('new'))) # If 'sess' evaluates false, user is not logged in in which # case we go directly to the "user" page which will say that # one has to be logged in. We do this instead of using jmcgi.- # err_page() because the notes on the users.jinja page inform # the user about the requirements for access. # If user is logged in but is not an Admin user, we ignore # the "u=..." url parameter and show user info only for # the logged in user. # If the user is an Admin user, we show info for the user # requested by the "u=..." parameter if any, or the logged # in user if not. # There may still be no user due to "u=..." for non-existant # or some corner-case but that's ok, page will show a "no user # found" message. user = userid = new = None if sess: # I.e., if logged in... if sess.priv == 'A': userid, new = fv('u'), fv('new') if not new and not userid: userid = sess.userid L('cgi.user').debug("userid=%r, new=%r" % (userid, new)) if userid: user = jmcgi.get_user(userid, svc, cfg) L('cgi.user').debug("read user data: %s" % (sanitize_o(user), )) L('cgi.user').debug("rendering template, new=%r" % new) jmcgi.jinja_page("user.jinja", user=user, result=fv('result'), session=sess, cfg=cfg, parms=parms, new=new, svc=svc, sid=sid, dbg=dbg, this_page='user.py')
def main (args, opts): jdb.reset_encoding (sys.stdout, 'utf-8') errs = [] try: form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform() except Exception as e: jmcgi.err_page ([str (e)]) entries = jmcgi.get_entrs (cur, form.getlist ('e'), form.getlist ('q'), errs) if errs: jmcgi.err_page (errs) # Add a .SEQKR attribute to each entry in 'entries' that # gives the kanji and reading of the newest (most recently # edited) entry that has the same sequence number. seqkr_decorate (entries) # Sort the entries. The sorting order will group entries # with the same sequence number (.src,.seq) together and # each of those groups will be ordered by the kanji/reading # of the newest (most recently edited) entry in the group. # (The kanji and/or readings of an entry are sometimes changed # and this order will keep the changed entries together with # their pre-changed versions, while maintaining an overall # ordering by kanji/reading.) Within each group having the # same sequence number, entries are sorted in descending order # by the timestamp of the most recent history; that is, from # the most recently edited entry to the least recently edited # one. entries.sort (key=lambda e: ( e.SEQKR[0], e.SEQKR[1], e.src, e.seq, # In case different seqs have same SEQKR. # e._hist[*].dt is a datatime.datetime instance. -(e._hist[-1].dt.timestamp() if e._hist else 0), -e.id)) for e in entries: for s in e._sens: if hasattr (s, '_xref'): jdb.augment_xrefs (cur, s._xref) if hasattr (s, '_xrer'): jdb.augment_xrefs (cur, s._xrer, 1) if hasattr (e, '_snd'): jdb.augment_snds (cur, e._snd) cur.close() disp = form.getfirst ('disp') if disp == 'xml': etxts = [fmtxml.entr (e) for e in entries] elif disp == 'jm': etxts = [fmtxml.entr (e, compat='jmdict') for e in entries] elif disp == 'jmne': etxts = [fmtxml.entr (e, compat='jmnedict') for e in entries] elif disp == 'jel': etxts = [fmtjel.entr (e) for e in entries] elif disp == 'ed': etxts = [xslfmt.entr (e) for e in entries] else: etxts = ['' for e in entries] jmcgi.htmlprep (entries) jmcgi.add_encodings (entries) # For kanjidic entries. if disp == 'ed': etxts = [jmcgi.txt2html (x) for x in etxts] jmcgi.add_filtered_xrefs (entries, rem_unap=True) if errs: jmcgi.err_page (errs) jmcgi.jinja_page ('entr.jinja', entries=list(zip(entries, etxts)), disp=disp, svc=svc, dbg=dbg, sid=sid, session=sess, cfg=cfg, parms=parms, this_page='entr.py')
def main(args, opts): jdb.reset_encoding(sys.stdout, 'utf-8') errs = [] so = None stats = {} try: form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform() except Exception as e: jmcgi.err_page([str(e)]) cfg_web = d2o(cfg['web']) cfg_srch = d2o(cfg['search']) fv = form.getfirst fl = form.getlist force_srchres = fv( 'srchres') # Force display of srchres page even if only one result. sqlp = (fv('sql') or '') soj = (fv('soj') or '') pgoffset = int(fv('p1') or 0) pgtotal = int(fv('pt') or -1) entrs_per_page = min( max(int(fv('ps') or cfg_web.DEF_ENTRIES_PER_PAGE), cfg_web.MIN_ENTRIES_PER_PAGE), cfg_web.MAX_ENTRIES_PER_PAGE) if not sqlp and not soj: so = jmcgi.SearchItems() so.idnum = fv('idval') so.idtyp = fv('idtyp') tl = [] for i in (1, 2, 3): txt = (fv('t' + str(i)) or '') if txt: tl.append( jmcgi.SearchItemsTexts(srchtxt=txt, srchin=fv('s' + str(i)), srchtyp=fv('y' + str(i)))) if tl: so.txts = tl so.pos = fl('pos') so.misc = fl('misc') so.fld = fl('fld') so.dial = fl('dial') so.rinf = fl('rinf') so.kinf = fl('kinf') so.freq = fl('freq') so.grp = grpsparse(fv('grp')) so.src = fl('src') so.stat = fl('stat') so.unap = fl('appr') so.nfval = fv('nfval') so.nfcmp = fv('nfcmp') # Search using gA freq criterion no longer supported. See # the comments in jmcgi._freqcond() but code left here for # reference. so.gaval = fv('gaval') so.gacmp = fv('gacmp') #FIXME? use selection boxes for dates? Or a JS calendar control? so.ts = dateparse(fv('ts0'), 0, errs), dateparse(fv('ts1'), 1, errs) so.smtr = (fv('smtr') or ''), fv('smtrm') so.mt = fv('mt') # Pack up all the search criteria in a json string that will # be given to the srchres form, which will in turn give it back # to us if the user want to display the "next page". soj = serialize.so2js(so) elif soj: # 'soj' is a json string that encodes the so object (containing # the search criteria) that were used in previous invocation # of this script, which displayed the previous page. so = serialize.js2so(soj) elif sqlp: # 'sqlp' is a SQL statement string that allows an arbitrary search. # Because it can also do other things such as delete the database, # it should only be run as a user with read-only access to the # database and it is the job of jmcgi.adv_srch_allowed() to check # that. if not jmcgi.adv_srch_allowed(cfg, sess): jmcgi.err_page(["'sql' parameter is disallowed."]) sql = sqlp.strip() if sql.endswith(';'): sql = sql[:-1] sql_args = [] if so: try: condlist = jmcgi.so2conds(so) except ValueError as e: errs.append(str(e)) # FIXME: [IS-115] Following will prevent kanjidic entries from # appearing in results. Obviously hardwiring id=4 is a hack. else: #condlist.append (('entr e', 'e.src!=4', [])) sql, sql_args = jdb.build_search_sql(condlist) if errs: jmcgi.err_page(errs) orderby = "ORDER BY __wrap__.kanj,__wrap__.rdng,__wrap__.seq,__wrap__.id" page = "OFFSET %s LIMIT %s" % (pgoffset, entrs_per_page) sql2 = "SELECT __wrap__.* FROM esum __wrap__ " \ "JOIN (%s) AS __user__ ON __user__.id=__wrap__.id %s %s" \ % (sql, orderby, page) stats['sql'] = sql stats['args'] = sql_args stats['orderby'] = orderby if cfg_srch.MAX_QUERY_COST > 0: try: cost = jdb.get_query_cost(cur, sql2, sql_args) except Exception as e: jmcgi.err_page(errs=[str(e)], cssclass="errormsg", prolog="Database error (%s)" % e.__class__.__name__) stats['cost'] = cost if cost > cfg_srch.MAX_QUERY_COST: jmcgi.err_page([ "The search request you made will likely take too " "long to execute. Please use your browser's \"back\" " "button to return to the search page and add more " "criteria to restrict your search more narrowly. " "(The estimated cost was %.1f, max allowed is %d.)" % (cost, cfg_srch.MAX_QUERY_COST) ]) t0 = time.time() try: rs = jdb.dbread(cur, sql2, sql_args) except Exception as e: #FIXME, what exception value(s)? jmcgi.err_page(errs=[str(e)], cssclass="errormsg", prolog="Database error (%s)" % e.__class__.__name__) stats['dbtime'] = time.time() - t0 reccnt = len(rs) if pgtotal < 0: if reccnt >= entrs_per_page: # If there may be more than one page of entries (because # 'reccnt' is greater than the page size, 'entrs_per_page', # then run another query to get the actual number of entries. # We only do this on the first page of results ('pgtotal' is # less then 0) and subsequently pass the value between pages # for performace reasons, even though the number of entries # may change before the user gets to the last page. sql3 = "SELECT COUNT(*) AS cnt FROM (%s) AS i " % sql cntrec = jdb.dbread(cur, sql3, sql_args) pgtotal = cntrec[0][0] # Total number of entries. else: pgtotal = reccnt if reccnt == 1 and pgtotal == 1 and not force_srchres: # If there is only one entry, display it rather than a search # results page. 'force_srchres' allows supressing this behavior # for debugging. svcstr = ("svc=%s&sid=%s&" % (svc, sid)) if svc else '' print("Location: entr.py?%se=%d\n" % (svcstr, rs[0].id)) else: jmcgi.jinja_page("srchres.jinja", results=rs, pt=pgtotal, p0=pgoffset, p1=pgoffset + reccnt, soj=soj, sql=sqlp, parms=parms, svc=svc, dbg=dbg, sid=sid, session=sess, cfg=cfg, stats=stats, this_page='srchres.py')
def main(args, opts): global Svc, Sid jdb.reset_encoding(sys.stdout, 'utf-8') errs = [] dbh = svc = None try: form, svc, dbg, dbh, sid, sess, parms, cfg = jmcgi.parseform() except ValueError as e: jmcgi.err_page([str(e)]) # Svc and Sid are used in function url() and are global in # in order to avoid having to pass them through several layers # of function calls. Svc, Sid = svc, sid L('cgi.edsubmit').debug("started: userid=%s, sid=%s" % (sess and sess.userid, sess and sess.id)) fv = form.getfirst # disp values: '': User submission, 'a': Approve. 'r': Reject; disp = fv('disp') or '' if not sess and disp: errs.append("Only registered editors can approve or reject entries") if errs: jmcgi.err_page(errs) try: entrs = serialize.unserialize(fv("entr")) except Exception: jmcgi.err_page(["Bad 'entr' parameter, unable to unserialize."]) added = [] # Clear any possible transactions begun elsewhere (e.g. by the # keyword table read in jdb.dbOpen()). Failure to do this will # cause the following START TRANSACTON command to fail with: # InternalError: SET TRANSACTION ISOLATION LEVEL must be # called before any query L('cgi.edsubmit.main').debug("starting transaction") dbh.connection.rollback() dbh.execute("START TRANSACTION ISOLATION LEVEL SERIALIZABLE") # FIXME: we unserialize the entr's xref's as they were resolved # by the edconf.py page. Should we check them again here? # If target entry was deleted in meantime, attempt to add # our entr to db will fail with obscure foreign key error. # Alternatively an edited version of target may have been # created which wont have our xref pointing to it as it should. for entr in entrs: # FIXME: submission() can raise a psycopg2 # TransactionRollbackError if there is a serialization # error resulting from a concurrent update. Detecting # such a condition is why run with serializable isolation # level. We need to trap it and present some sensible # error message. e = submission(dbh, entr, disp, errs, jmcgi.is_editor(sess), sess.userid if sess else None) # The value returned by submission() is a 3-tuple consisting # of (id, seq, src) for the added entry. if e: added.append(e) if errs: L('cgi.edsubmit.main').info("rolling back transaction due to errors") dbh.connection.rollback() jmcgi.err_page(errs) else: L('cgi.edsubmit.main').info("doing commit") dbh.connection.commit() jmcgi.jinja_page("submitted.jinja", added=added, parms=parms, svc=svc, dbg=dbg, sid=sid, session=sess, cfg=cfg, this_page='edsubmit.py') L('cgi.edsubmit.main').debug("thank you page sent, exiting normally")
def main(args, opts): jdb.reset_encoding(sys.stdout, 'utf-8') errs = [] entrs = [] try: form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform() except Exception as e: jmcgi.err_page([str(e)]) fv = form.getfirst fl = form.getlist is_editor = jmcgi.is_editor(sess) dbg = fv('dbg') meth = fv('meth') def_corp = fv('c') # Default corpus for new entries. defcorpid = None if def_corp: try: def_corp = int(def_corp) except ValueError: pass try: defcorpid = jdb.KW.SRC[def_corp].id except KeyError: errs.append("Bad url parameter: c=%s" % def_corp) force_corp = fv('f') # Force default corpus for new entries. sentrs = fl("entr") for sentr in sentrs: try: entrs = serialize.unserialize(sentr) except Exception as e: errs.append("Bad 'entr' value, unable to unserialize: %s" % str(e)) else: entrs.append(entr) jentrs = fl('j') for jentr in jentrs: try: entr = edparse.entr(jentr) except Exception as e: errs.append("Bad 'j' value, unable to parse: %s" % str(e)) else: entr.src = None entrs.append(entr) elist, qlist, active = fl('e'), fl('q'), fv('a') if elist or qlist: entrs.extend( jmcgi.get_entrs(cur, elist or [], qlist or [], errs, active=active, corpus=def_corp) or []) cur.close() if (elist or qlist or jentrs or sentrs) and not entrs: # The caller explictly specified and entry to edit but we # didn't find it (or them). Rather than treating this as # though no entries were given and displaying a blank edit # form, show an error message. errs.append("No matching entries were found") if errs: jmcgi.err_page(errs) srcs = sorted(jdb.KW.recs('SRC'), key=lambda x: x.kw.lower()) #srcs.insert (0, jdb.Obj (id=0, kw='', descr='')) if not entrs: # This is a blank new entry. # The following dummy entry will produce the default # text for new entries: no kanji, no reading, and sense # text "[1][n]". entr = jdb.Entr( _sens=[jdb.Sens(_pos=[jdb.Pos(kw=jdb.KW.POS['n'].id)])], src=None) entrs = [entr] for e in entrs: if not is_editor: remove_freqs(e) e.ISDELETE = (e.stat == jdb.KW.STAT['D'].id) or None # Provide a default corpus. if not e.src: e.src = defcorpid e.NOCORPOPT = force_corp if errs: jmcgi.err_page(errs) for e in entrs: e.ktxt = fmtjel.kanjs(e._kanj) e.rtxt = fmtjel.rdngs(e._rdng, e._kanj) e.stxt = fmtjel.senss(e._sens, e._kanj, e._rdng) if errs: jmcgi.err_page(errs) jmcgi.jinja_page('edform.jinja', parms=parms, extra={}, entrs=entrs, srcs=srcs, is_editor=is_editor, svc=svc, dbg=dbg, sid=sid, session=sess, cfg=cfg, this_page='edform.py')
def main(args, opts): jdb.reset_encoding(sys.stdout, 'utf-8') errs = [] so = None stats = {} try: form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform() except Exception as e: jmcgi.err_page([str(e)]) fv = form.getfirst fl = form.getlist # The form values "userid", "fullname", "email", "priv", # "disabled", come from editable fields in the user.py # page. # The values "new" (i.e. create) and "delete" are also user # boolean input from user.py indicating what the user wants # to do. Neither of them set indicates an update action on # an existing account. Both of them set is an error. # The form value "subjid" identifies the user whose data was # originally loaded into the user.py form and is the user any # update or delete will be performed on. If it differs from # sess.userid it indcates the action is to e done on the # account of someone other than the logged user themself # and is prohibited unless the logged in user has "admin" # privilege. For a new (create) action, "subjid" is ignored # and the new user is created with the id given in "userid". # Set 'action' to "n" (new), "u" (update), "d" (delete) or # "x" (invalid) according to the values of fv('new') and # fv('delete') that were received from as url parameters # from the User form. action = {(0,0):'u', (0,1):'d', (1,0):'n', (1,1):'x'}\ [(bool(fv('new')),bool(fv('delete')))] L('cgi.userupd').debug( "new=%r, delete=%r, action=%r, subjid=%r, userid=%r" % (fv('new'), fv('delete'), action, fv('subjid'), fv('userid'))) # NOTE: The jmcgi.err_page() calls below do not return, # jmcgi.err_page() calls sys.exit(). if not sess: jmcgi.err_page([], prolog="<p>You must login before you can change your " "user settings.</p>") if fv('subjid') != sess.userid and sess.priv != 'A': jmcgi.err_page( [], prolog="<p>You do not have sufficient privilege to alter " "settings for anyone other than yourself.</p>") if action in ('nd') and sess.priv != 'A': jmcgi.err_page( [], prolog="<p>You do not have sufficient privilege to create " "or delete users.</p>") if action == 'x': jmcgi.err_page( [], prolog="<p>\"New user\" and \"Delete\" are incompatible.</p>") errors = [] # Get the id of the user we will be updating. If creating a # new user, 'subjid' should not exist and thus 'subj' will be # None which has the beneficial effect of causing gen_sql_- # params() to generate change parameters for every form value # which is what we want when creating a user. subj = jmcgi.get_user(fv('subjid'), svc, cfg) if action in 'nu': # "new" or "update" action... if action == 'u': L('cgi.userupd').debug("update user %r" % sanitize_o(subj)) else: L('cgi.userupd').debug("create user %r" % fv('userid')) if action == 'n' and \ (subj or fv('userid')==sess.userid or jmcgi.get_user(fv('userid'), svc, cfg)): # This is the creation of a new user (fv('userid')). # The userid must not already exist. The tests for # subj and sess.userid are simply to avoid an expensive # get_user() call when we already know the user exists. errors.append("Account name %s is already in use." % fv('userid')) if action == 'u' and fv('userid')!=subj.userid \ and (fv('userid')==sess.userid \ or jmcgi.get_user(fv('userid'), svc, cfg)): # This is an update of an existing user. # If the new userid (fv('userid')) is the same as the # subj.userid it's not being changed and is ok. If # different then it must not be the same as an exiting # userid. The test for sess.userid is simply to avoid # an expensive get_user() call when we already know # that user exists. errors.append("Account name %s is already in use." % fv('userid')) # Get the parameters we'll need for the sql statement used # to update the user/sessions database. collist, values, err \ = gen_sql_params (sess.priv=='A', subj, fv('pw1'), fv('pw2'), fv('userid'), fv('fullname'), fv('email'), fv('priv'), fv('disabled')) errors.extend(err) L('cgi.userupd').debug("collist: %r" % collist) L('cgi.userupd').debug("values: %r" % sanitize_v(values, collist)) else: # "delete" action... # We ignore changes made to the form fields since we # are going to delete the user, they are irrelevant. # Except for one: the "userid" field. If that was # changed we treat it as an error due to the risk that # the user thought the changed userid will be deleted # which is not what will happen (we delete the "subjid" # user.) values = [] if fv('userid') != fv('subjid'): errors.append("Can't delete user when userid has been changed.") if not subj: errors.append("User '%s' doesn't exist." % fv('subjid')) if errors: jmcgi.err_page( errs=errors, prolog="The following errors were found in the changes " "you requested. Please use your browser's Back button " "to return to the user page, correct them, and resubmit " "your changes.") update_session = None result = None summary = 'not available' if action == 'n': # Create new user... cols = ','.join(c for c, p in collist) pmarks = ','.join(p for c, p in collist) sql = "INSERT INTO users(%s) VALUES (%s)" % (cols, pmarks) values_sani = sanitize_v(values, collist) summary = "added user \"%s\"" \ % ''.join(p for c,p in collist if c=='userid') elif action == 'd': # Delete existing user... sql = "DELETE FROM users WHERE userid=%s" values.append(fv('subjid')) values_sani = values summary = "deleted user \"%s\"" % fv('subjid') else: # Update existing user... if not collist: result = 'nochange' else: if subj and subj.userid == sess.userid \ and fv('userid') and fv('userid'): update_session = fv('userid') updclause = ','.join(("%s=%s" % (c, p)) for c, p in collist) sql = "UPDATE users SET %s WHERE userid=%%s" % updclause values.append(fv('subjid')) values_sani = sanitize_v(values, collist) summary = "updated user %s (%s)" \ % (fv('subjid'), ','.join([c for c,p in collist])) if result != 'nochange': sesscur = jdb.dbOpenSvc(cfg, svc, session=True, nokw=True) L('cgi.userupd.db').debug("sql: %r" % sql) # 'values_sani' should be the same as values but with any # password text masked out. L('cgi.userupd.db').debug("args: %r" % values_sani) sesscur.execute(sql, values) sesscur.connection.commit() #FIXME: trap db errors and try to figure out what went # wrong in terms that a user can remediate. if update_session: L('cgi.userupd').debug("update sess.userid: %r->%r" % (sess.userid, update_session)) sess.userid = update_session L('cgi.userupd').info(summary) result = 'success' # If the user is not an admin we send them back to their # settings page (using 'userid' since it they may have changed # it.) For admin users it's more complcatd because they might # have deleted the user. Easiest for us to send him/her back # to the user list page which we know always exists. if sess.priv == 'A': return_to = 'users.py?' else: return_to = 'user.py?u=%s' % fv('userid') jmcgi.redirect(urlbase() + "%s&svc=%s&sid=%s&dbg=%s&result=%s" % (return_to, svc, sid, dbg, result))
def main(args, opts): jdb.reset_encoding(sys.stdout, 'utf-8') errs = [] chklist = {} try: form, svc, dbg, cur, sid, sess, parms, cfg = jmcgi.parseform() except Exception as e: jmcgi.err_page([str(e)]) fv = form.getfirst fl = form.getlist KW = jdb.KW # 'eid' will be an integer if we are editing an existing # entry, or undefined if this is a new entry. pentr = None eid = url_int('id', form, errs) if eid: # Get the parent entry of the edited entry. This is what the # edited entry will be diff'd against for the history record. # It is also the entry that will be pointed to by the edited # entry's 'dfrm' field. pentr = jdb.entrList(cur, None, [eid]) #FIXME: Need a better message with more explanation. if not pentr: errs.append("The entry you are editing has been deleted.") else: pentr = pentr[0] # Desired disposition: 'a':approve, 'r':reject, undef:submit. disp = url_str('disp', form) if disp != 'a' and disp != 'r' and disp != '' and disp is not None: errs.append("Invalid 'disp' parameter: '%s'" % disp) # New status is A for edit of existing or new entry, D for # deletion of existing entry. delete = fv('delete') makecopy = fv('makecopy') if delete and makecopy: errs.append( "The 'delete' and 'treat as new'" " checkboxes are mutually exclusive; please select only one.") if makecopy: eid = None # FIXME: we need to disallow new entries with corp.seq # that matches an existing A, A*, R*, D*, D? entry. # Do same check in submit.py. seq = url_int('seq', form, errs) src = url_int('src', form, errs) notes = url_str('notes', form) srcnote = url_str('srcnote', form) # These are the JEL (JMdict Edit Language) texts which # we will concatenate into a string that is fed to the # JEL parser which will create an Entr object. kanj = (stripws(url_str('kanj', form))).strip() rdng = (stripws(url_str('rdng', form))).strip() sens = (url_str('sens', form)).strip() intxt = "\f".join((kanj, rdng, sens)) grpstxt = url_str('grp', form) # Get the meta-edit info which will go into the history # record for this change. comment = url_str('comment', form) refs = url_str('reference', form) name = url_str('name', form) email = url_str('email', form) if errs: jmcgi.err_page(errs) # Parse the entry data. Problems will be reported # by messages in 'perrs'. We do the parse even if # the request is to delete the entry (is this right # thing to do???) since on the edconf page we want # to display what the entry was. The edsubmit page # will do the actual deletion. entr, errs = parse(intxt) # 'errs' is a list which if not empty has a single item # which is a 2-seq of str's: (error-type, error-message). if errs or not entr: if not entr and not errs: errs = ([], "Unable to create an entry from your input.") jmcgi.err_page([errs[0][1]], prolog=errs[0][0], cssclass="errormsg") entr.dfrm = eid entr.unap = not disp # To display the xrefs and reverse xrefs in html, they # need to be augmented with additional info about their # targets. collect_refs() simply returns a list Xref # objects that are on the entr argument's .xref list # (forward xrefs) if rev not true, or the Xref objects # on the entr argument's ._xrer list (reverse xrefs) if # rev is true). This does not remove them from the entry # and is done simply for convenience so we can have # augment_xrefs() process them all in one shot. # augment_xrefs add an attribute, .TARG, to each Xref # object whose value is an Entr object for the entry the # xref points to if rev is not true, or the entry the xref # is from, if rev is true. These Entr objects can be used # to display info about the xref target or source such as # seq#, reading or kanji. See jdb.augment_xrefs() for details. # Note that <xrefs> and <xrers> below contain references # to the xrefs on the entries; thus the augmentation done # by jdb.augment_xrefs() alters the xref objects on those # entries. if pentr: x = jdb.collect_xrefs([pentr]) if x: jdb.augment_xrefs(cur, x) # Although we don't allow editing of an entry's reverse # xref, we still augment them (on the parent entry) # because we will display them. x = jdb.collect_xrefs([pentr], rev=True) if x: jdb.augment_xrefs(cur, x, rev=True) x = jdb.collect_xrefs([entr]) if x: jdb.augment_xrefs(cur, x) if delete: # Ignore any content changes made by the submitter by # restoring original values to the new entry. entr.seq = pentr.seq entr.src = pentr.src entr.stat = KW.STAT['D'].id entr.notes = pentr.notes entr.srcnote = pentr.srcnote entr._kanj = getattr(pentr, '_kanj', []) entr._rdng = getattr(pentr, '_rdng', []) entr._sens = getattr(pentr, '_sens', []) entr._snd = getattr(pentr, '_snd', []) entr._grp = getattr(pentr, '_grp', []) entr._cinf = getattr(pentr, '_cinf', []) else: # Migrate the entr details to the new entr object # which to this point has only the kanj/rdng/sens # info provided by jbparser. entr.seq = seq entr.src = src entr.stat = KW.STAT['A'].id entr.notes = notes entr.srcnote = srcnote entr._grp = jelparse.parse_grp(grpstxt) # This form and the JEL parser provide no way to change # some entry attributes such _cinf, _snd, reverse xrefs # and for non-editors, _freq. We need to copy these items # from the original entry to the new, edited entry to avoid # loosing them. The copy can be shallow since we won't be # changing the copied content. if pentr: if not jmcgi.is_editor(sess): jdb.copy_freqs(pentr, entr) if hasattr(pentr, '_cinf'): entr._cinf = pentr._cinf copy_snd(pentr, entr) # Copy the reverse xrefs that are on pentr to entr, # removing any that are no longer valid because they # refer to senses , readings or kanji no longer present # on the edited entry. Note that these have already # been augmented above. nuked_xrers = realign_xrers(entr, pentr) if nuked_xrers: chklist['xrers'] = format_for_warnings(nuked_xrers, pentr) # Add sound details so confirm page will look the same as the # original entry page. Otherwise, the confirm page will display # only the sound clip id(s). #FIXME? Should the following snd augmentation stuff be outdented # one level so that it is done in both the delete and non-delete # paths? snds = [] for s in getattr(entr, '_snd', []): snds.append(s) for r in getattr(entr, '_rdng', []): for s in getattr(r, '_snd', []): snds.append(s) if snds: jdb.augment_snds(cur, snds) # If any xrefs were given, resolve them to actual entries # here since that is the form used to store them in the # database. If any are unresolvable, an approriate error # is saved and will reported later. rslv_errs = jelparse.resolv_xrefs(cur, entr) if rslv_errs: chklist['xrslv'] = rslv_errs if errs: jmcgi.err_page(errs) # Append a new hist record details this edit. if not hasattr(entr, '_hist'): entr._hist = [] entr = jdb.add_hist(entr, pentr, sess.userid if sess else None, name, email, comment, refs, entr.stat == KW.STAT['D'].id) if not delete: check_for_errors(entr, errs) if errs: jmcgi.err_page(errs) pseq = pentr.seq if pentr else None check_for_warnings(cur, entr, pseq, chklist) # The following all expect a list of entries. jmcgi.add_filtered_xrefs([entr], rem_unap=False) serialized = serialize.serialize([entr]) jmcgi.htmlprep([entr]) entrs = [[entr, None]] # Package 'entr' as expected by entr.jinja. jmcgi.jinja_page("edconf.jinja", entries=entrs, serialized=serialized, chklist=chklist, disp=disp, parms=parms, svc=svc, dbg=dbg, sid=sid, session=sess, cfg=cfg, this_page='edconf.py')