def open_environment(env_path, mpr): env = Environment.Environment(env_path) version = env.get_version() if version < Environment.db_version: raise TracError('The Trac environment needs to be upgraded. ' 'Run "trac-admin %s upgrade"' % env_path) elif version > Environment.db_version: raise TracError('Unknown Trac Environment version (%d).' % version) env.href = Href.Href(mpr.cgi_location) env.abs_href = Href.Href(mpr.base_url) return env
def open_environment(): env_path = os.getenv('TRAC_ENV') if not env_path: raise EnvironmentError, \ 'Missing environment variable "TRAC_ENV". Trac ' \ 'requires this variable to point to a valid Trac Environment.' env = Environment.Environment(env_path) version = env.get_version() if version < Environment.db_version: raise TracError('The Trac Environment needs to be upgraded. ' 'Run "trac-admin %s upgrade"' % env_path) elif version > Environment.db_version: raise TracError('Unknown Trac Environment version (%d).' % version) return env
def get_session(self, sid): self.sid = sid curs = self.db.cursor() curs.execute("SELECT username,var_name,var_value FROM session" " WHERE sid=%s", self.sid) rows = curs.fetchall() if (not rows # No session data yet or rows[0][0] == 'anonymous' # Anon session or rows[0][0] == self.req.authname): # Session is mine for u,k,v in rows: self.vars[k] = v self.update_sess_time() self.bake_cookie() self.populate_hdf() return if self.req.authname == 'anonymous': err = ('Session cookie requires authentication. <p>' 'Please choose action:</p>' '<ul><li><a href="%s">Log in and continue session</a></li>' '<li><a href="%s?newsession=1">Create new session (no login required)</a></li>' '</ul>' % (self.env.href.login(), self.env.href.settings())) else: err = ('Session belongs to another authenticated user.' '<p><a href="%s?newsession=1">' 'Create new session</a></p>' % self.env.href.settings()) raise TracError(err, 'Error accessing authenticated session')
def commit(self, author, comment, remote_addr): if self.new: self.perm.assert_permission(perm.WIKI_CREATE) else: self.perm.assert_permission(perm.WIKI_MODIFY) if self.readonly: self.perm.assert_permission(perm.WIKI_ADMIN) cursor = self.db.cursor() if not self.modified and self.readonly != self.old_readonly: cursor.execute( 'UPDATE wiki SET readonly=%s WHERE name=%s and VERSION=%s', self.readonly, self.name, self.version - 1) self.db.commit() self.old_readonly = self.readonly elif self.modified: cursor.execute( 'INSERT INTO WIKI ' '(name, version, time, author, ipnr, text, comment, readonly) ' 'VALUES (%s, %s, %s, %s, %s, %s, %s, %s)', self.name, self.version, int(time.time()), author, remote_addr, self.text, comment, self.readonly) self.db.commit() self.old_readonly = self.readonly self.modified = 0 else: del cursor raise TracError('Page not modified')
def generate_diff(self, pagename, version): import Diff Diff.get_options(self.env, self.req, self.args) if self.args.has_key('update'): self.req.redirect(self.env.href.wiki(pagename, version, 1)) cursor = self.db.cursor() cursor.execute( 'SELECT text,author,comment,time FROM wiki ' 'WHERE name=%s AND (version=%s or version=%s)' 'ORDER BY version ASC', pagename, version - 1, version) res = cursor.fetchall() if not res: raise TracError( 'Version %d of page "%s" not found.' % (version, pagename), 'Page Not Found') if len(res) == 1: old = '' else: old = res[0][0].splitlines() new = res[-1][0].splitlines() author = res[-1][1] or '' comment = res[-1][2] or '' time_str = time.strftime('%c', time.localtime(int(res[-1][3]))) self.req.hdf.setValue('wiki.version', str(version)) self.req.hdf.setValue('wiki.diff.time', time_str) self.req.hdf.setValue('wiki.diff.author', escape(author)) self.req.hdf.setValue('wiki.diff.comment', escape(comment)) builder = Diff.HDFBuilder(self.req.hdf, 'wiki.diff') builder.writeline('header %s %d | %s %d redaeh' % (pagename, version - 1, pagename, version)) builder.writeline('@@ -1,%d +1,%d @@' % (len(old), len(new))) try: for line in difflib.Differ().compare(old, new): if line != ' ': builder.writeline(line) except AttributeError: raise TracError('Python >= 2.2 is required for diff support.') builder.close()
def create_milestone(self, name, date=0, descr=''): self.perm.assert_permission(perm.MILESTONE_CREATE) if not name: raise TracError('You must provide a name for the milestone.', 'Required Field Missing') cursor = self.db.cursor() self.log.debug("Creating new milestone '%s'" % name) cursor.execute( "INSERT INTO milestone (id, name, time, descr) " "VALUES (NULL, %s, %d, %s)", name, date, descr) self.db.commit() self.req.redirect(self.env.href.milestone(name))
def change_sid(self, newsid): if newsid == self.sid: return curs = self.db.cursor() curs.execute("SELECT sid FROM session WHERE sid=%s", newsid) if curs.fetchone(): raise TracError("Session '%s' already exists.<br />" "Please choose a different session id." % newsid, "Error renaming session") curs.execute("UPDATE session SET sid=%s WHERE sid=%s", newsid, self.sid) self.db.commit() self.sid = newsid self.bake_cookie()
def parse_date(self, datestr): seconds = None datestr = datestr.strip() for format in [ '%x %X', '%x, %X', '%X %x', '%X, %x', '%x', '%c', '%b %d, %Y' ]: try: date = time.strptime(datestr, format) seconds = time.mktime(date) break except ValueError: continue if seconds == None: raise TracError('%s is not a known date format.' % datestr, 'Invalid Date Format') return seconds
def get_milestone(self, name): cursor = self.db.cursor() cursor.execute( "SELECT name, time, descr FROM milestone " "WHERE name = %s ORDER BY time, name", name) row = cursor.fetchone() cursor.close() if not row: raise TracError('Milestone %s does not exist.' % name, 'Invalid Milestone Number') milestone = {'name': row['name']} descr = row['descr'] if descr: milestone['descr_source'] = descr milestone['descr'] = wiki_to_html(descr, self.req.hdf, self.env, self.db) t = row['time'] and int(row['time']) if t > 0: milestone['date'] = time.strftime('%x', time.localtime(t)) return milestone
def notify(self, resid, subject): self.subject = subject enabled = self.env.get_config('notification', 'smtp_enabled', '0') if not enabled.lower() in TRUE: return self.smtp_server = self.env.get_config('notification', 'smtp_server', self.smtp_server) self.from_email = self.env.get_config('notification', 'smtp_from', '') self.replyto_email = self.env.get_config('notification', 'smtp_replyto', self.from_email) self.from_email = self.from_email or self.replyto_email if not self.from_email and not self.replyto_email: raise TracError( 'Unable to send email due to identity crisis. <br />' 'Both <b>notification.from</b> and' ' <b>notification.reply_to</b> are unspecified' ' in configuration.', 'SMTP Notification Error') Notify.notify(self, resid)
def save_milestone(self, id): self.perm.assert_permission(perm.MILESTONE_MODIFY) if self.args.has_key('save'): name = self.args.get('name', '') if not name: raise TracError('You must provide a name for the milestone.', 'Required Field Missing') datemode = self.args.get('datemode', 'manual') if datemode == 'now': date = int(time.time()) else: datestr = self.args.get('date', '') date = 0 if datestr: date = self.parse_date(datestr) descr = self.args.get('descr', '') if not id: self.create_milestone(name, date, descr) else: self.update_milestone(id, name, date, descr) elif id: self.req.redirect(self.env.href.milestone(id)) else: self.req.redirect(self.env.href.roadmap())
def render(self): name = self.args.get('page', 'WikiStart') author = self.args.get('author', get_reporter_id(self.req)) edit_version = self.args.get('edit_version', None) delete_ver = self.args.get('delete_ver', None) delete_page = self.args.get('delete_page', None) comment = self.args.get('comment', '') save = self.args.get('save', None) edit = self.args.get('edit', None) diff = self.args.get('diff', None) cancel = self.args.get('cancel', None) preview = self.args.get('preview', None) history = self.args.get('history', None) version = int(self.args.get('version', 0)) readonly = self.args.get('readonly', None) # Ask web spiders to not index old version if diff or version: self.req.hdf.setValue('html.norobots', '1') if cancel: self.req.redirect(self.env.href.wiki(name)) # Not reached if delete_ver and edit_version and name: # Delete only a specific page version self.perm.assert_permission(perm.WIKI_DELETE) cursor = self.db.cursor() cursor.execute('DELETE FROM wiki WHERE name=%s and version=%s', name, int(edit_version)) self.db.commit() self.log.info('Deleted version %d of page %s' % (int(edit_version), name)) if int(edit_version) > 1: self.req.redirect(self.env.href.wiki(name)) else: # Delete orphaned attachments for attachment in self.env.get_attachments( self.db, 'wiki', name): self.env.delete_attachment(self.db, 'wiki', name, attachment[0]) self.req.redirect(self.env.href.wiki()) # Not reached if delete_page and name: # Delete a wiki page completely self.perm.assert_permission(perm.WIKI_DELETE) cursor = self.db.cursor() cursor.execute('DELETE FROM wiki WHERE name=%s', name) self.db.commit() self.log.info('Deleted version %d of page ' + name) # Delete orphaned attachments for attachment in self.env.get_attachments(self.db, 'wiki', name): self.env.delete_attachment(self.db, 'wiki', name, attachment[0]) self.req.redirect(self.env.href.wiki()) # Not reached self.req.hdf.setValue('wiki.name', escape(name)) self.req.hdf.setValue('wiki.author', escape(author)) self.req.hdf.setValue('wiki.comment', escape(comment)) # Workaround so that we can attach files to wiki pages # even if the page name contains a '/' self.req.hdf.setValue('wiki.namedoublequoted', urllib.quote(urllib.quote(name, ''))) session = Session(self.env, self.req) editrows = self.args.get('editrows') if editrows: self.req.hdf.setValue('wiki.edit_rows', editrows) pref = session.get('wiki_editrows', '20') if editrows != pref: session.set_var('wiki_editrows', editrows) else: self.req.hdf.setValue('wiki.edit_rows', session.get('wiki_editrows', '20')) if save: self.req.hdf.setValue('wiki.action', 'save') elif edit: self.perm.assert_permission(perm.WIKI_MODIFY) self.req.hdf.setValue('wiki.action', 'edit') self.req.hdf.setValue('title', escape(name) + ' (edit)') elif preview: self.req.hdf.setValue('wiki.action', 'preview') self.req.hdf.setValue('wiki.scroll_bar_pos', self.args.get('scroll_bar_pos', '')) self.req.hdf.setValue('title', escape(name) + ' (preview)') elif diff and version > 0: self.req.hdf.setValue('wiki.action', 'diff') self.generate_diff(name, version) self.req.hdf.setValue('title', escape(name) + ' (diff)') elif history: self.req.hdf.setValue('wiki.action', 'history') self.generate_history(name) self.req.hdf.setValue('title', escape(name) + ' (history)') else: self.perm.assert_permission(perm.WIKI_VIEW) if version: self.add_link('alternate', '?version=%d&format=txt' % version, 'Plain Text', 'text/plain') else: self.add_link('alternate', '?format=txt', 'Plain Text', 'text/plain') if self.args.has_key('text'): del self.args['text'] self.req.hdf.setValue('wiki.action', 'view') if name == 'WikiStart': self.req.hdf.setValue('title', '') else: self.req.hdf.setValue('title', escape(name)) self.env.get_attachments_hdf(self.db, 'wiki', name, self.req.hdf, 'wiki.attachments') self.page = WikiPage(name, version, self.perm, self.db) if self.args.has_key('text'): self.page.set_content(self.args.get('text')) else: self.page.modified = 0 # Modify the read-only flag if it has been changed and the user is WIKI_ADMIN if save and self.perm.has_permission(perm.WIKI_ADMIN): if readonly: self.page.readonly = 1 else: self.page.readonly = 0 self.req.hdf.setValue('wiki.readonly', str(self.page.readonly)) # We store the page version when we start editing a page. # This way we can stop users from saving changes if they are # not based on the latest version any more if edit_version: self.req.hdf.setValue('wiki.edit_version', edit_version) else: self.req.hdf.setValue('wiki.edit_version', str(self.page.version)) if save and edit_version != str(self.page.version - 1): raise TracError('Sorry, Cannot create new version, this page has ' 'already been modified by someone else.') if save: self.page.commit(author, comment, self.req.remote_addr) self.req.redirect(self.env.href.wiki(self.page.name)) self.req.hdf.setValue('wiki.current_href', escape(self.env.href.wiki(self.page.name))) self.req.hdf.setValue( 'wiki.history_href', escape(self.env.href.wiki(self.page.name, history=1))) self.req.hdf.setValue('wiki.page_name', escape(self.page.name)) self.req.hdf.setValue('wiki.page_source', escape(self.page.text)) out = StringIO.StringIO() Formatter(self.req.hdf, self.env, self.db).format(self.page.text, out) self.req.hdf.setValue('wiki.page_html', out.getvalue())
def perform_query (self, query, changeset, tickets, wiki, page=0): if not query: return ([], 0) keywords = query.split(' ') if changeset: changeset = self.perm.has_permission(perm.CHANGESET_VIEW) if tickets: tickets = self.perm.has_permission(perm.TICKET_VIEW) if wiki: wiki = self.perm.has_permission(perm.WIKI_VIEW) if changeset == tickets == wiki == 0: return ([], 0) if len(keywords) == 1: kwd = keywords[0] redir = None # Prepending a '!' disables quickjump feature if kwd[0] == '!': keywords[0] = kwd[1:] query = query[1:] self.req.hdf.setValue('search.q', query) # Ticket quickjump elif kwd[0] == '#' and kwd[1:].isdigit(): redir = self.env.href.ticket(kwd[1:]) # Changeset quickjump elif kwd[0] == '[' and kwd[-1] == ']' and kwd[1:-1].isdigit(): redir = self.env.href.changeset(kwd[1:-1]) # Report quickjump elif kwd[0] == '{' and kwd[-1] == '}' and kwd[1:-1].isdigit(): redir = self.env.href.report(kwd[1:-1]) elif kwd[0].isupper() and kwd[1].islower(): r = "((^|(?<=[^A-Za-z]))[!]?[A-Z][a-z/]+(?:[A-Z][a-z/]+)+)" if re.match (r, kwd): redir = self.env.href.wiki(kwd) if redir: self.req.hdf.setValue('search.q', '') self.req.redirect(redir) elif len(query) < 3: raise TracError('Search query too short. ' 'Query must be at least 3 characters long.', 'Search Error') cursor = self.db.cursor () q = [] if changeset: q.append('SELECT 1 as type, message AS title, message, author, ' ' \'\' AS keywords, rev AS data, time,0 AS ver' ' FROM revision WHERE %s OR %s' % (self.query_to_sql(query, 'message'), self.query_to_sql(query, 'author'))) if tickets: q.append('SELECT DISTINCT 2 as type, a.summary AS title, ' ' a.description AS message, a.reporter AS author, ' ' a.keywords as keywords, a.id AS data, a.time as time, 0 AS ver' ' FROM ticket a LEFT JOIN ticket_change b ON a.id = b.ticket' ' WHERE (b.field=\'comment\' AND %s ) OR' ' %s OR %s OR %s OR %s OR %s' % (self.query_to_sql(query, 'b.newvalue'), self.query_to_sql(query, 'summary'), self.query_to_sql(query, 'keywords'), self.query_to_sql(query, 'description'), self.query_to_sql(query, 'reporter'), self.query_to_sql(query, 'cc'))) if wiki: q.append('SELECT 3 as type, text AS title, text AS message,' ' author, \'\' AS keywords, w1.name AS data, time,' ' w1.version as ver' ' FROM wiki w1, ' ' (SELECT name,max(version) AS ver ' ' FROM wiki GROUP BY name) w2' ' WHERE w1.version = w2.ver AND w1.name = w2.name AND' ' (%s OR %s OR %s) ' % (self.query_to_sql(query, 'w1.name'), self.query_to_sql(query, 'w1.author'), self.query_to_sql(query, 'w1.text'))) if not q: return [] q_str = string.join(q, ' UNION ALL ') q_str += ' ORDER BY 7 DESC LIMIT %d OFFSET %d' % \ (self.RESULTS_PER_PAGE + 1, self.RESULTS_PER_PAGE * page) self.log.debug("SQL Query: %s" % q_str) cursor.execute(q_str) # Make the data more HDF-friendly info = [] more = 0 while 1: row = cursor.fetchone() if not row: break if len(info) == self.RESULTS_PER_PAGE: more = 1 break msg = row['message'] t = time.localtime(int(row['time'])) item = {'type': int(row['type']), 'keywords': row['keywords'] or '', 'data': row['data'], 'title': escape(row['title'] or ''), 'datetime' : time.strftime('%c', t), 'author': escape(row['author'])} if item['type'] == 1: item['changeset_href'] = self.env.href.changeset(int(row['data'])) elif item['type'] == 2: item['ticket_href'] = self.env.href.ticket(int(row['data'])) elif item['type'] == 3: item['wiki_href'] = self.env.href.wiki(row['data']) item['shortmsg'] = escape(shorten_line(msg)) item['message'] = escape(self.shorten_result(msg, keywords)) info.append(item) return info, more