def client_list(viewer): if permission_check(viewer, "client", "read") or permission_is_root(viewer): result = [] for client in Client.query().filter(Client.active == True): result.append(to_model(client)) return result else: raise NotAllowedError()
def client_http_put(actor, client_id, **kwargs): key = client_key(client_id) client = key.get() if client: if permission_check(actor, "client", "update") or permission_is_root(actor): client_update(actor, client=client, **kwargs) else: raise NotAllowedError() else: client_http_post(actor, key=key, client_id=client_id, **kwargs)
def task_http_put(actor, task_ids, **kwargs): key = task_key(task_ids) task = key.get() if task: if permission_check(actor, "task", "update") or permission_is_root(actor): task_update(actor, task=task, **kwargs) else: raise NotAllowedError() else: task_http_post(actor, key=key, task_ids=task_ids, **kwargs)
def tag_http_put(actor, tag_ids, **kwargs): key = tag_key(tag_ids) tag = key.get() if tag: if permission_check(actor, "tag", "update") or permission_is_root(actor): tag_update(actor, tag=tag, **kwargs) else: raise NotAllowedError() else: tag_http_post(actor, key=key, tag_ids=tag_ids, **kwargs)
def project_http_put(actor, client_id, project_ids, **kwargs): key = project_key(client_id, project_ids) project = key.get() if project: if permission_check(actor, "project", "update") or permission_is_root(actor): project_update(actor, project=project, **kwargs) else: raise NotAllowedError() else: project_http_post(actor, key=key, project_ids=project_ids, **kwargs)
def tag_list(viewer, target): log.debug("Listing tags for %s" % target) if permission_check(viewer, "tag", "view") or permission_is_root(viewer): log.debug("Listing tags for %s" % target) result = [] for applied in AppliedTag.query(AppliedTag.target == target, ancestor=target).filter(): result.append(tag_key_to_path(applied.tag)) return result else: log.debug("Not allowed")
def tag_remove(viewer, target, tag, **ignored): if permission_check(viewer, "tag", "remove") or permission_is_root(viewer): key = tag_key(tag) applied = AppliedTag.query(AppliedTag.tag == key, AppliedTag.target == target, ancestor=target).get(keys_only=True) if applied: applied.delete() log.debug("Tag removed") else: log.debug("Tag not applied") else: log.debug("Not allowed")
def issue_search(viewer, simple=None, query=None, complex=None): permission_verify(viewer, "issue", "read") if not complex: if query: complex = query_to_complex_search(query) else: # Status is open and assigned to me, or closing and verified by me. complex = { "boolean" : "or", "sub" : [ { "boolean" : "and", "sub" : [ { "field" : "status", "operator" : "in", "value" : [ "triage", "assigned", "working" ] }, { "field" : "assignees", "operator" : "==", "value" : [ viewer ] } ] }, { "boolean" : "and", "sub" : [ { "field" : "status", "operator" : "in", "value" : [ "fixed", "rejected" ] }, { "field" : "verifiers", "operator" : "==", "value" : [ viewer ] } ] } ] } result = [] ndb_query, first_sort = complex_search_to_ndb_query(complex) if permission_is_root(viewer): if ndb_query: dataset = Issue.query().filter(ndb_query) else: dataset = Issue.query().filter() else: privacy_query = ndb.OR(Issue.privacy == "public", Issue.assignees == build_user_key(viewer), Issue.reporters == build_user_key(viewer), Issue.verifiers == build_user_key(viewer), Issue.cc == build_user_key(viewer)) if ndb_query: dataset = Issue.query().filter(ndb.AND(ndb_query, privacy_query)) else: dataset = Issue.query().filter(privacy_query) if first_sort: dataset = dataset.order(first_sort) else: dataset = dataset.order(-Issue.score, -Issue.created) for issue in dataset: issue.history = [] result.append(to_model(viewer, issue)) return result
def tag_apply(viewer, target, tag, **ignored): if permission_check(viewer, "tag", "apply") or permission_is_root(viewer): key = tag_key(tag) if not AppliedTag.query(AppliedTag.tag == key, AppliedTag.target == target, ancestor=target).get(): new_tag = AppliedTag(parent=target) new_tag.applied_by = build_user_key(viewer) new_tag.tag = key new_tag.target = target new_tag.put() log.debug("Tag %s applied" % key) return "/tags/%s" % "/".join(tag) else: log.debug("Tag already applied") else: log.debug("Not allowed")
def issue_get(viewer, issue_id=None, key=None, issue=None, silent=False): result = issue or (key or issue_key(issue_id)).get() if result: if result.privacy == "public" or \ build_user_key(viewer) in result.cc + result.assignees + result.reporters + result.verifiers or \ permission_is_root(viewer): result.history = remark_list(viewer, result.key) return result elif silent: return None else: raise NotAllowedError() elif silent: return None else: raise NotFoundError()
def task_load(viewer, task_ids=None): if permission_check(viewer, "task", "read") or permission_is_root(viewer): key = task_key(task_ids) parent = None children = [] for child in Task.query(Task.parent == key, ancestor=key): if child.active: children.append(to_model(child)) if task_ids: task = to_model(key.get()) if task: if key.parent(): parent = to_model(key.parent().get()) task["parent"] = parent task["children"] = children return task else: return children else: log.debug("Not allowed")
def project_load(viewer, client_id, project_ids=None): if permission_check(viewer, "project", "read") or permission_is_root(viewer): key = project_key(client_id, project_ids) parent = None children = [] for child in Project.query(Project.parent == key, ancestor=key): if child.active: children.append(to_model(child)) if project_ids: project = to_model(key.get()) if project: if key.parent(): parent = to_model(key.parent().get()) project["parent"] = parent project["children"] = children return project else: return children else: log.debug("Not allowed")
def project_http_delete(actor, client_id, project_ids, **ignored): if permission_check(actor, "project", "delete") or permission_is_root(actor): project_deactivate(actor, client_id, project_ids=project_ids) else: raise NotAllowedError()
def client_http_post(actor, **kwargs): if permission_check(actor, "client", "create") or permission_is_root(actor): client_create(actor, **kwargs) else: raise NotAllowedError()
def project_http_post(actor, **kwargs): if permission_check(actor, "project", "create") or permission_is_root(actor): project_create(actor, **kwargs) else: raise NotAllowedError()
def task_http_delete(actor, task_ids, **ignored): if permission_check(actor, "task", "delete") or permission_is_root(actor): task_deactivate(actor, task_ids=task_ids) else: raise NotAllowedError()
def issue_update(actor, issue_id=None, key=None, issue=None, summary=undefined, project=undefined, status=undefined, priority=undefined, severity=undefined, reporters=undefined, assignees=undefined, verifiers=undefined, cc=undefined, depends_on=undefined, blocking=undefined, privacy=undefined, due_date=undefined, body="", send_mail=True, blobs=undefined, **args): issue = issue or (key or issue_key(issue_id)).get() header = "" is_root = permission_is_root(actor) if not is_root and issue.privacy != "public" and \ build_user_key(actor) not in issue.cc + issue.assignees + issue.reporters + issue.verifiers: raise NotAllowedError() blob_list = None to_recipients = set([]) if issue.assignees: to_recipients.update(issue.assignees) if issue.reporters: to_recipients.update(issue.reporters) if issue.verifiers: to_recipients.update(issue.verifiers) cc_recipients = set(issue.cc) if is_root or issue.privacy != "secure" or build_user_key(actor) in issue.assignees + issue.verifiers: # Rewrite input types if necessary def fix_users(field): log.debug(field) if is_undefined(field): return undefined if not field: return undefined if isinstance(field, basestring): return set([build_user_key(id) for id in re.split("[\\s,;]+", field) if len(id) > 0]) return [build_user_key(user) for user in field] reporters = fix_users(reporters) assignees = fix_users(assignees) verifiers = fix_users(verifiers) cc = fix_users(cc) if is_defined(depends_on): depends_on = set([issue_key(id) for id in re.split("[\\s,;]+", depends_on) if len(id) > 0]) if is_defined(blocking): blocking = set([issue_key(id) for id in re.split("[\\s,;]+", blocking) if len(id) > 0]) if is_defined(due_date): if due_date == "": due_date = None else: if "timezoneoffset" in args: offset = datetime.timedelta(minutes=int(args["timezoneoffset"])) client_time = datetime.datetime.utcnow() - offset parsed_time = lib.parsedatetime.Calendar().parse(due_date, client_time) log.debug("client_time = %s" % client_time) else: offset = datetime.timedelta(0) parsed_time = lib.parsedatetime.Calendar().parse(due_date) if parsed_time[1] == 1: due_date = datetime.datetime(*parsed_time[0][:3]) + offset else: due_date = datetime.datetime(*parsed_time[0][:6]) + offset # Update all fields if is_defined(summary) and summary != issue.summary: header = header + "**Summary:** " + summary + " \n" issue.summary = summary issue.summary_index = set(re.split("[^\\w\\d]+", summary.lower())) if is_defined(project) and project != issue.project: header = header + "**Project:** " + project + " \n" issue.project = project if is_defined(status) and status != issue.status: if not status in issue_transitions: raise IllegalError("Status not recognized") if not status in issue_transitions[issue.status]: raise IllegalError("Status transition not allowed") header = header + "**Status:** " + status + " \n" issue.status = status if is_defined(priority) and int(priority) != issue.priority: header = header + "**Priority:** " + str(priority) + " \n" issue.priority = int(priority) if is_defined(severity) and int(severity) != issue.severity: header = header + "**Severity:** " + str(severity) + " \n" issue.severity = int(severity) if is_defined(reporters) and reporters != set(issue.reporters): log.debug("Reporters: %s" % reporters) header = header + "**Reporters:** " + ", ".join([user.id() for user in reporters]) + " \n" issue.reporters = reporters if is_defined(assignees) and assignees != set(issue.assignees): header = header + "**Assignees:** " + ", ".join([user.id() for user in assignees]) + " \n" issue.assignees = assignees if is_defined(verifiers) and verifiers != set(issue.verifiers): header = header + "**Verifiers:** " + ", ".join([user.id() for user in verifiers]) + " \n" issue.verifiers = verifiers if is_defined(cc) and cc != set(issue.cc): header = header + "**CC:** " + ", ".join([user.id() for user in cc]) + " \n" issue.cc = list(cc) if is_defined(depends_on) and depends_on != set(issue.depends_on): header = header + "**Depends On:** " + ", ".join([str(iss.id()) for iss in depends_on]) + " \n" issue.depends_on = list(depends_on) if is_defined(blocking) and blocking != set(issue.blocking): header = header + "**Blocking:** " + ", ".join([str(iss.id()) for iss in blocking]) + " \n" issue.blocking = list(blocking) if is_defined(privacy) and privacy != issue.privacy: header = header + "**Privacy:** " + privacy + " \n" issue.privacy = privacy if is_defined(due_date) and due_date != issue.due_date: header = header + "**Due Date:** " + str(due_date) + " UTC \n" issue.due_date = due_date if is_defined(blobs) and blobs: blob_list = build_blob_keys(blobs) header = header + "**Attachments:** %s File(s) \n" % len(blob_list) # Fix up missing stuff if not issue.reporters: issue.reporters = [ build_user_key(actor) ] if not issue.verifiers: issue.verifiers = [ build_user_key(actor) ] if not issue.assignees: issue.assignees = [ build_user_key(actor) ] to_recipients.update(issue.assignees) to_recipients.update(issue.reporters) to_recipients.update(issue.verifiers) cc_recipients.update(issue.cc) issue.score, issue.score_description = calculate_issue_score(issue) issue.text_index = set(issue.text_index) | \ set(issue.summary_index) | \ set(re.split("[^\\w\\d]+", body.lower())) issue.updated_by = build_user_key(actor) issue.put() issue.history = [ remark_create(actor, issue.key, body.strip(), header.strip(), blobs=blob_list) ] if send_mail: settings = get_system_settings() if "host" in settings and settings["host"] and settings["host"] != "": host = settings["host"] else: host = "%s.appspot.com" % app_identity.get_application_id() message_id = "<issue-%s@%s>" % (issue.key.id(), app_identity.get_application_id()) url = "http://%s/issues/%s" % (host, issue.key.id()) text = "%s\n\n%s\n\n%s" % (header, body, url) html = "<div style='font-size: 0.8em'>%s</div><div>%s</div><div>%s</div>" % \ (lib.markdown.markdown(header), lib.markdown.markdown(body), url) try: if len(cc_recipients) > 0: mail.send_mail(sender=actor.user.email(), to=[user.id() for user in to_recipients], cc=[user.id() for user in cc_recipients], reply_to=actor.user.email(), subject="[" + str(issue.key.id()) + "] " + issue.summary, body=text, html=html, headers={"In-Reply-To": message_id, "References": message_id }) else: mail.send_mail(sender=actor.user.email(), to=[user.id() for user in to_recipients], reply_to=actor.user.email(), subject="[" + str(issue.key.id()) + "] " + issue.summary, body=text, html=html, headers={"In-Reply-To": message_id, "References": message_id }) log.debug("Email sent to %s" % (to_recipients | cc_recipients)) except: log.warn("Email quota exceeded, email not sent") log.debug(text) return to_model(actor, issue)
def task_http_post(actor, **kwargs): if permission_check(actor, "task", "create") or permission_is_root(actor): task_create(actor, **kwargs) else: raise NotAllowedError()
def issue_update(actor, issue_id=None, key=None, issue=None, summary=undefined, project=undefined, status=undefined, priority=undefined, severity=undefined, reporters=undefined, assignees=undefined, verifiers=undefined, cc=undefined, depends_on=undefined, blocking=undefined, privacy=undefined, due_date=undefined, body="", send_mail=True, blobs=undefined, **args): issue = issue or (key or issue_key(issue_id)).get() header = "" is_root = permission_is_root(actor) if not is_root and issue.privacy != "public" and \ build_user_key(actor) not in issue.cc + issue.assignees + issue.reporters + issue.verifiers: raise NotAllowedError() blob_list = None to_recipients = set([]) if issue.assignees: to_recipients.update(issue.assignees) if issue.reporters: to_recipients.update(issue.reporters) if issue.verifiers: to_recipients.update(issue.verifiers) cc_recipients = set(issue.cc) if is_root or issue.privacy != "secure" or build_user_key( actor) in issue.assignees + issue.verifiers: # Rewrite input types if necessary def fix_users(field): log.debug(field) if is_undefined(field): return undefined if not field: return undefined if isinstance(field, basestring): return set([ build_user_key(id) for id in re.split("[\\s,;]+", field) if len(id) > 0 ]) return [build_user_key(user) for user in field] reporters = fix_users(reporters) assignees = fix_users(assignees) verifiers = fix_users(verifiers) cc = fix_users(cc) if is_defined(depends_on): depends_on = set([ issue_key(id) for id in re.split("[\\s,;]+", depends_on) if len(id) > 0 ]) if is_defined(blocking): blocking = set([ issue_key(id) for id in re.split("[\\s,;]+", blocking) if len(id) > 0 ]) if is_defined(due_date): if due_date == "": due_date = None else: if "timezoneoffset" in args: offset = datetime.timedelta( minutes=int(args["timezoneoffset"])) client_time = datetime.datetime.utcnow() - offset parsed_time = lib.parsedatetime.Calendar().parse( due_date, client_time) log.debug("client_time = %s" % client_time) else: offset = datetime.timedelta(0) parsed_time = lib.parsedatetime.Calendar().parse(due_date) if parsed_time[1] == 1: due_date = datetime.datetime(*parsed_time[0][:3]) + offset else: due_date = datetime.datetime(*parsed_time[0][:6]) + offset # Update all fields if is_defined(summary) and summary != issue.summary: header = header + "**Summary:** " + summary + " \n" issue.summary = summary issue.summary_index = set(re.split("[^\\w\\d]+", summary.lower())) if is_defined(project) and project != issue.project: header = header + "**Project:** " + project + " \n" issue.project = project if is_defined(status) and status != issue.status: if not status in issue_transitions: raise IllegalError("Status not recognized") if not status in issue_transitions[issue.status]: raise IllegalError("Status transition not allowed") header = header + "**Status:** " + status + " \n" issue.status = status if is_defined(priority) and int(priority) != issue.priority: header = header + "**Priority:** " + str(priority) + " \n" issue.priority = int(priority) if is_defined(severity) and int(severity) != issue.severity: header = header + "**Severity:** " + str(severity) + " \n" issue.severity = int(severity) if is_defined(reporters) and reporters != set(issue.reporters): log.debug("Reporters: %s" % reporters) header = header + "**Reporters:** " + ", ".join( [user.id() for user in reporters]) + " \n" issue.reporters = reporters if is_defined(assignees) and assignees != set(issue.assignees): header = header + "**Assignees:** " + ", ".join( [user.id() for user in assignees]) + " \n" issue.assignees = assignees if is_defined(verifiers) and verifiers != set(issue.verifiers): header = header + "**Verifiers:** " + ", ".join( [user.id() for user in verifiers]) + " \n" issue.verifiers = verifiers if is_defined(cc) and cc != set(issue.cc): header = header + "**CC:** " + ", ".join( [user.id() for user in cc]) + " \n" issue.cc = list(cc) if is_defined(depends_on) and depends_on != set(issue.depends_on): header = header + "**Depends On:** " + ", ".join( [str(iss.id()) for iss in depends_on]) + " \n" issue.depends_on = list(depends_on) if is_defined(blocking) and blocking != set(issue.blocking): header = header + "**Blocking:** " + ", ".join( [str(iss.id()) for iss in blocking]) + " \n" issue.blocking = list(blocking) if is_defined(privacy) and privacy != issue.privacy: header = header + "**Privacy:** " + privacy + " \n" issue.privacy = privacy if is_defined(due_date) and due_date != issue.due_date: header = header + "**Due Date:** " + str(due_date) + " UTC \n" issue.due_date = due_date if is_defined(blobs) and blobs: blob_list = build_blob_keys(blobs) header = header + "**Attachments:** %s File(s) \n" % len( blob_list) # Fix up missing stuff if not issue.reporters: issue.reporters = [build_user_key(actor)] if not issue.verifiers: issue.verifiers = [build_user_key(actor)] if not issue.assignees: issue.assignees = [build_user_key(actor)] to_recipients.update(issue.assignees) to_recipients.update(issue.reporters) to_recipients.update(issue.verifiers) cc_recipients.update(issue.cc) issue.score, issue.score_description = calculate_issue_score(issue) issue.text_index = set(issue.text_index) | \ set(issue.summary_index) | \ set(re.split("[^\\w\\d]+", body.lower())) issue.updated_by = build_user_key(actor) issue.put() issue.history = [ remark_create(actor, issue.key, body.strip(), header.strip(), blobs=blob_list) ] if send_mail: settings = get_system_settings() if "host" in settings and settings["host"] and settings["host"] != "": host = settings["host"] else: host = "%s.appspot.com" % app_identity.get_application_id() message_id = "<issue-%s@%s>" % (issue.key.id(), app_identity.get_application_id()) url = "http://%s/issues/%s" % (host, issue.key.id()) text = "%s\n\n%s\n\n%s" % (header, body, url) html = "<div style='font-size: 0.8em'>%s</div><div>%s</div><div>%s</div>" % \ (lib.markdown.markdown(header), lib.markdown.markdown(body), url) try: if len(cc_recipients) > 0: mail.send_mail(sender=actor.user.email(), to=[user.id() for user in to_recipients], cc=[user.id() for user in cc_recipients], reply_to=actor.user.email(), subject="[" + str(issue.key.id()) + "] " + issue.summary, body=text, html=html, headers={ "In-Reply-To": message_id, "References": message_id }) else: mail.send_mail(sender=actor.user.email(), to=[user.id() for user in to_recipients], reply_to=actor.user.email(), subject="[" + str(issue.key.id()) + "] " + issue.summary, body=text, html=html, headers={ "In-Reply-To": message_id, "References": message_id }) log.debug("Email sent to %s" % (to_recipients | cc_recipients)) except: log.warn("Email quota exceeded, email not sent") log.debug(text) return to_model(actor, issue)
def issue_search(viewer, simple=None, query=None, complex=None): permission_verify(viewer, "issue", "read") if not complex: if query: complex = query_to_complex_search(query) else: # Status is open and assigned to me, or closing and verified by me. complex = { "boolean": "or", "sub": [{ "boolean": "and", "sub": [{ "field": "status", "operator": "in", "value": ["triage", "assigned", "working"] }, { "field": "assignees", "operator": "==", "value": [viewer] }] }, { "boolean": "and", "sub": [{ "field": "status", "operator": "in", "value": ["fixed", "rejected"] }, { "field": "verifiers", "operator": "==", "value": [viewer] }] }] } result = [] ndb_query, first_sort = complex_search_to_ndb_query(complex) if permission_is_root(viewer): if ndb_query: dataset = Issue.query().filter(ndb_query) else: dataset = Issue.query().filter() else: privacy_query = ndb.OR(Issue.privacy == "public", Issue.assignees == build_user_key(viewer), Issue.reporters == build_user_key(viewer), Issue.verifiers == build_user_key(viewer), Issue.cc == build_user_key(viewer)) if ndb_query: dataset = Issue.query().filter(ndb.AND(ndb_query, privacy_query)) else: dataset = Issue.query().filter(privacy_query) if first_sort: dataset = dataset.order(first_sort) else: dataset = dataset.order(-Issue.score, -Issue.created) for issue in dataset: issue.history = [] result.append(to_model(viewer, issue)) return result
def client_http_delete(actor, client_id, **ignored): if permission_check(actor, "client", "delete") or permission_is_root(actor): client_deactivate(actor, client_id=client_id) else: raise NotAllowedError()
def client_load(viewer, client_id=None, key=None): if permission_check(viewer, "client", "read") or permission_is_root(viewer): return to_model((key or client_key(client_id)).get()) else: raise NotAllowedError()