def parseReviewFilters(db, data): reviewfilters = [] for filter_data in data: filter_username = filter_data["username"] filter_type = filter_data["type"] filter_path = filter_data["path"] filter_user = dbutils.User.fromName(db, filter_username) if not filter_user: raise OperationError("no such user: '******'" % filter_username) filter_directory_id = 0 filter_file_id = 0 if filter_path != "/": if filter_path[-1] == "/" or dbutils.is_directory(filter_path): filter_directory_id = dbutils.find_directory(db, path=filter_path) else: filter_file_id = dbutils.find_file(db, path=filter_path) reviewfilters.append((filter_directory_id, filter_file_id, filter_type, None, filter_user.id)) return reviewfilters
def process(self, db, creator, review_id, filters): review = dbutils.Review.fromId(db, review_id) by_user = {} for filter in filters: if "user_ids" in filter: user_ids = set(filter["user_ids"]) else: user_ids = set([]) if "user_names" in filter: for user_name in filter["user_names"]: user_ids.add(dbutils.User.fromName(db, user_name).id) if "directory_ids" in filter: directory_ids = set(filter["directory_ids"]) else: directory_ids = set([]) if "file_ids" in filter: file_ids = set(filter["file_ids"]) else: file_ids = set([]) if "paths" in filter: for path in filter["paths"]: if not path or path == "/": directory_ids.add(0) elif path.endswith("/") or dbutils.is_directory( db, path) or ("." not in path.split("/")[-1] and not dbutils.is_file(db, path)): directory_ids.add(dbutils.find_directory(db, path)) else: file_ids.add(dbutils.find_file(db, path)) for user_id in user_ids: reviewer_directory_ids, reviewer_file_ids, watcher_directory_ids, watcher_file_ids = by_user.setdefault( user_id, (set(), set(), set(), set())) if filter["type"] == "reviewer": reviewer_directory_ids |= directory_ids reviewer_file_ids |= file_ids else: watcher_directory_ids |= directory_ids watcher_file_ids |= file_ids pending_mails = [] for user_id, args in by_user.items(): user = dbutils.User.fromId(db, user_id) pending_mails.extend( review_utils.addReviewFilters(db, creator, user, review, *args)) db.commit() mailutils.sendPendingMails(pending_mails) return OperationResult()
def showfilters(req, db, user): user = dbutils.User.fromName(db, req.getParameter("user", req.user)) path = req.getParameter("path") repository = gitutils.Repository.fromParameter(db, req.getParameter("repository", user.getPreference(db, "defaultRepository"))) path = path.rstrip("/") if dbutils.is_directory(db, path): directory_id = dbutils.find_directory(db, path=path) show_path = path + "/" cursor = db.cursor() cursor.execute("SELECT name FROM files WHERE directory=%s ORDER BY id ASC LIMIT 1", (directory_id,)) row = cursor.fetchone() if row: path += "/" + row[0] else: path += "/dummy.txt" else: show_path = path file_id = dbutils.find_file(db, path=path) filters = review_filters.Filters() filters.load(db, repository=repository, recursive=True) reviewers = [] watchers = [] for user_id, (filter_type, _delegate) in filters.listUsers(db, file_id).items(): if filter_type == 'reviewer': reviewers.append(user_id) else: watchers.append(user_id) result = "Path: %s\n" % show_path reviewers_found = False watchers_found = False for reviewer_id in sorted(reviewers): if not reviewers_found: result += "\nReviewers:\n" reviewers_found = True reviewer = dbutils.User.fromId(db, reviewer_id) result += " %s <%s>\n" % (reviewer.fullname, reviewer.email) for watcher_id in sorted(watchers): if not watchers_found: result += "\nWatchers:\n" watchers_found = True watcher = dbutils.User.fromId(db, watcher_id) result += " %s <%s>\n" % (watcher.fullname, watcher.email) if not reviewers_found and not watchers_found: result += "\nNo matching filters found.\n" return result
def process(self, db, creator, review_id, filters): review = dbutils.Review.fromId(db, review_id) by_user = {} for filter in filters: if "user_ids" in filter: user_ids = set(filter["user_ids"]) else: user_ids = set([]) if "user_names" in filter: for user_name in filter["user_names"]: user_ids.add(dbutils.User.fromName(db, user_name).id) if "directory_ids" in filter: directory_ids = set(filter["directory_ids"]) else: directory_ids = set([]) if "file_ids" in filter: file_ids = set(filter["file_ids"]) else: file_ids = set([]) if "paths" in filter: for path in filter["paths"]: if not path or path == "/": directory_ids.add(0) elif path.endswith("/") or dbutils.is_directory(db, path) or ("." not in path.split("/")[-1] and not dbutils.is_file(db, path)): directory_ids.add(dbutils.find_directory(db, path)) else: file_ids.add(dbutils.find_file(db, path)) for user_id in user_ids: reviewer_directory_ids, reviewer_file_ids, watcher_directory_ids, watcher_file_ids = by_user.setdefault(user_id, (set(), set(), set(), set())) if filter["type"] == "reviewer": reviewer_directory_ids |= directory_ids reviewer_file_ids |= file_ids else: watcher_directory_ids |= directory_ids watcher_file_ids |= file_ids pending_mails = [] for user_id, args in by_user.items(): user = dbutils.User.fromId(db, user_id) pending_mails.extend(review_utils.addReviewFilters(db, creator, user, review, *args)) db.commit() mailutils.sendPendingMails(pending_mails) return OperationResult()
def addfilter(req, db, user): if user.isAnonymous(): return OperationFailureMustLogin() cursor = db.cursor() repository_id = req.getParameter("repository", filter=int) filter_type = req.getParameter("type") filter_path = req.getParameter("path") filter_delegate = req.getParameter("delegate", "") force = req.getParameter("force", "no") == "yes" repository = gitutils.Repository.fromId(db, repository_id) if filter_delegate: invalid_users = [] for delegate_name in map(str.strip, filter_delegate.split(',')): if dbutils.User.fromName(db, delegate_name) is None: invalid_users.append(delegate_name) if invalid_users: return "error:invalid-users:%s" % ','.join(invalid_users) if filter_path == '/': directory_id, file_id = 0, 0 elif filter_path[-1] == '/': directory_id, file_id = dbutils.find_directory(db, path=filter_path[:-1]), 0 else: if not force and dbutils.is_directory(db, filter_path): return "error:directory" else: directory_id, file_id = dbutils.find_directory_file(db, filter_path) if directory_id: specificity = len(dbutils.explode_path(db, directory_id=directory_id)) if file_id: specificity += 1 else: specificity = 0 cursor.execute("INSERT INTO filters (uid, repository, directory, file, specificity, type, delegate) VALUES (%s, %s, %s, %s, %s, %s, %s)", [user.id, repository.id, directory_id, file_id, specificity, filter_type, ','.join(map(str.strip, filter_delegate.split(',')))]) user.setPreference(db, "email.activated", True) db.commit() return "ok:directory=%d,file=%d" % (directory_id, file_id)
def renderSearch(req, db, user): summary_value = req.getParameter("summary", None) summary_mode_value = req.getParameter("summarymode", None) branch_value = req.getParameter("branch", None) owner_value = req.getParameter("owner", None) path_value = req.getParameter("path", None) document = htmlutils.Document(req) document.setTitle("Search") html = document.html() head = html.head() body = html.body() page.utils.generateHeader(body, db, user, current_page="search") document.addExternalStylesheet("resource/search.css") document.addExternalScript("resource/search.js") document.addInternalScript(user.getJS()) cursor = db.cursor() cursor.execute("SELECT DISTINCT name, fullname FROM users JOIN reviewusers ON (reviewusers.uid=users.id) WHERE reviewusers.owner") users = [("{ label: %s, value: %s }" % (htmlutils.jsify("%s (%s)" % (fullname, name)), htmlutils.jsify(name))) for name, fullname in cursor] document.addInternalScript("var users = [ %s ];" % ", ".join(users)) search = page.utils.PaleYellowTable(body, "Search") def renderSummary(target): target.input(name="summary", value=summary_value or "") summary_mode = target.select(name="summary_mode") summary_mode.option(value="all", selected="selected" if summary_mode_value == "all" else None).text("All words") summary_mode.option(value="any", selected="selected" if summary_mode_value == "any" else None).text("Any word") def renderBranch(target): target.input(name="branch", value=branch_value or "") def renderOwner(target): target.input(name="owner", value=owner_value or "") def renderPath(target): target.input(name="path", value=path_value or "") def renderButton(target): target.button(onclick="search();").text("Search") search.addItem("Summary", renderSummary, "Words occurring in the review's summary.") search.addItem("Branch", renderBranch, "Name of review branch.") search.addItem("Owner", renderOwner, "Owner of the review.") search.addItem("Path", renderPath, "Path (file or directory) that the review contains changes in.") search.addCentered(renderButton) if summary_value is not None: summary_value = summary_value.strip() if branch_value is not None: branch_value = branch_value.strip() if owner_value is not None: owner_value = owner_value.strip() if path_value is not None: path_value = path_value.strip() if summary_value or branch_value or owner_value or path_value: query = """SELECT DISTINCT reviews.id, reviews.summary, branches.name FROM %s WHERE %s""" tables = ["reviews", "branches ON (branches.id=reviews.branch)"] conditions = [] arguments = [] if summary_value: words = summary_value.split() operator = " AND " if summary_mode_value == "all" else " OR " conditions.append("(%s)" % operator.join(["reviews.summary ~* %s"] * len(words))) arguments.extend([".*\\m" + word + "\\M.*" for word in words]) if branch_value: def globToSQLPattern(glob): pattern = glob.replace("\\", "\\\\").replace("%", "\\%").replace("?", "_").replace("*", "%") if pattern[0] != "%": pattern = "%" + pattern if pattern[-1] != "%": pattern = pattern + "%" return pattern conditions.append("branches.name LIKE %s") arguments.append(globToSQLPattern(branch_value)) if owner_value: owner = dbutils.User.fromName(db, owner_value) tables.append("reviewusers ON (reviewusers.review=reviews.id)") conditions.append("reviewusers.uid=%s") conditions.append("reviewusers.owner") arguments.append(owner.id) if path_value: file_ids = dbutils.contained_files(db, dbutils.find_directory(db, path_value)) if path_value[-1] != '/': file_ids.append(dbutils.find_file(db, path_value)) tables.append("reviewfiles ON (reviewfiles.review=reviews.id)") conditions.append("reviewfiles.file=ANY (%s)") arguments.append(file_ids) query = """SELECT DISTINCT reviews.id, reviews.summary, branches.name FROM %s WHERE %s ORDER BY reviews.id""" % (" JOIN ".join(tables), " AND ".join(conditions)) cursor.execute(query, arguments) table = body.div("main").table("paleyellow reviews", align="center") table.col(width="20%") table.col(width="80%") header = table.tr().td("h1", colspan=4).h1() header.text("Reviews") for review_id, summary, branch_name in cursor: row = table.tr("review") row.td("name").text(branch_name) row.td("title").a(href="r/%d" % review_id).text(summary) return document
modules.add(moduleFromFile(file_id)) teams_per_modules.setdefault(frozenset(modules), set()).update(team) for modules, team in teams_per_modules.items(): row = shared.tr("reviewers") cell = row.td("reviewers") members = sorted([dbutils.User.fromId(db, user_id).fullname for user_id in team]) for member in members: cell.text(member).br() row.td("willreview").innerHTML("<span class='also'>also</span> review changes in") cell = row.td("files") for path in diff.File.eliminateCommonPrefixes(sorted(modules)): cell.span("file").innerHTML(path).br() directory_ids = "[ %s ]" % ", ".join([str(dbutils.find_directory(db, path=path[:-1])) for path in modules if path.endswith("/")]) file_ids = "[ %s ]" % ", ".join([str(dbutils.find_file(db, path=path)) for path in modules if not path.endswith("/")]) user_ids = "[ %s ]" % ", ".join(map(str, team)) cell = row.td("buttons") cell.button("accept", critic_directory_ids=directory_ids, critic_file_ids=file_ids, critic_user_ids=user_ids).text("I will review this!") cell.button("deny", critic_directory_ids=directory_ids, critic_file_ids=file_ids, critic_user_ids=user_ids).text("They will review this!") yield flush(target) profiler.check("shared assignments") cursor.execute("SELECT batches.id, users.fullname, batches.comment, batches.time FROM batches JOIN users ON (users.id=batches.uid) WHERE batches.review=%s ORDER BY batches.id DESC", [review.id]) rows = cursor.fetchall() if rows:
def renderSearch(req, db, user): summary_value = req.getParameter("summary", None) summary_mode_value = req.getParameter("summarymode", None) branch_value = req.getParameter("branch", None) owner_value = req.getParameter("owner", None) path_value = req.getParameter("path", None) document = htmlutils.Document(req) document.setTitle("Search") html = document.html() head = html.head() body = html.body() page.utils.generateHeader(body, db, user, current_page="search") document.addExternalStylesheet("resource/search.css") document.addExternalScript("resource/search.js") document.addInternalScript(user.getJS()) cursor = db.cursor() cursor.execute( "SELECT DISTINCT name, fullname FROM users JOIN reviewusers ON (reviewusers.uid=users.id) WHERE reviewusers.owner" ) users = [("{ label: %s, value: %s }" % (htmlutils.jsify("%s (%s)" % (fullname, name)), htmlutils.jsify(name))) for name, fullname in cursor] document.addInternalScript("var users = [ %s ];" % ", ".join(users)) search = page.utils.PaleYellowTable(body, "Search") def renderSummary(target): target.input(name="summary", value=summary_value or "") summary_mode = target.select(name="summary_mode") summary_mode.option(value="all", selected="selected" if summary_mode_value == "all" else None).text("All words") summary_mode.option(value="any", selected="selected" if summary_mode_value == "any" else None).text("Any word") def renderBranch(target): target.input(name="branch", value=branch_value or "") def renderOwner(target): target.input(name="owner", value=owner_value or "") def renderPath(target): target.input(name="path", value=path_value or "") def renderButton(target): target.button(onclick="search();").text("Search") search.addItem("Summary", renderSummary, "Words occurring in the review's summary.") search.addItem("Branch", renderBranch, "Name of review branch.") search.addItem("Owner", renderOwner, "Owner of the review.") search.addItem( "Path", renderPath, "Path (file or directory) that the review contains changes in.") search.addCentered(renderButton) if summary_value is not None: summary_value = summary_value.strip() if branch_value is not None: branch_value = branch_value.strip() if owner_value is not None: owner_value = owner_value.strip() if path_value is not None: path_value = path_value.strip() if summary_value or branch_value or owner_value or path_value: query = """SELECT DISTINCT reviews.id, reviews.summary, branches.name FROM %s WHERE %s""" tables = ["reviews", "branches ON (branches.id=reviews.branch)"] conditions = [] arguments = [] if summary_value: words = summary_value.split() operator = " AND " if summary_mode_value == "all" else " OR " conditions.append( "(%s)" % operator.join(["reviews.summary ~* %s"] * len(words))) arguments.extend([".*\\m" + word + "\\M.*" for word in words]) if branch_value: def globToSQLPattern(glob): pattern = glob.replace("\\", "\\\\").replace("%", "\\%").replace( "?", "_").replace("*", "%") if pattern[0] != "%": pattern = "%" + pattern if pattern[-1] != "%": pattern = pattern + "%" return pattern conditions.append("branches.name LIKE %s") arguments.append(globToSQLPattern(branch_value)) if owner_value: owner = dbutils.User.fromName(db, owner_value) tables.append("reviewusers ON (reviewusers.review=reviews.id)") conditions.append("reviewusers.uid=%s") conditions.append("reviewusers.owner") arguments.append(owner.id) if path_value: file_ids = dbutils.contained_files( db, dbutils.find_directory(db, path_value)) if path_value[-1] != '/': file_ids.append(dbutils.find_file(db, path_value)) tables.append("reviewfiles ON (reviewfiles.review=reviews.id)") conditions.append("reviewfiles.file=ANY (%s)") arguments.append(file_ids) query = """SELECT DISTINCT reviews.id, reviews.summary, branches.name FROM %s WHERE %s ORDER BY reviews.id""" % (" JOIN ".join(tables), " AND ".join(conditions)) cursor.execute(query, arguments) table = body.div("main").table("paleyellow reviews", align="center") table.col(width="20%") table.col(width="80%") header = table.tr().td("h1", colspan=4).h1() header.text("Reviews") for review_id, summary, branch_name in cursor: row = table.tr("review") row.td("name").text(branch_name) row.td("title").a(href="r/%d" % review_id).text(summary) return document