def __init__(self, timestamp, days_only=False): values = [] if timestamp: date_str = timestr.FormatRelativeDate(timestamp, days_only=days_only) if not date_str: date_str = timestr.FormatAbsoluteDate(timestamp) values = [date_str] TableCell.__init__(self, CELL_TYPE_UNFILTERABLE, values)
def _GetUserViewAndFormattedTime(self, mr, user_id, timestamp): formatted_time = (timestr.FormatAbsoluteDate(timestamp) if timestamp else None) user = self.services.user.GetUser(mr.cnxn, user_id) if user_id else None user_view = None if user: user_view = framework_views.UserView(user) viewing_self = mr.auth.user_id == user_id # Do not obscure email if current user is a site admin. Do not obscure # email if current user is the same as the creator. For all other # cases do whatever obscure_email setting for the user is. email_obscured = (not(mr.auth.user_pb.is_site_admin or viewing_self) and user_view.obscure_email) if not email_obscured: user_view.RevealEmail() return user_view, formatted_time
def __init__(self, issue, users_by_id, config): """Store relevant values for later display by EZT. Args: issue: An Issue protocol buffer. users_by_id: dict {user_id: UserViews} for all users mentioned in issue. config: ProjectIssueConfig for this issue. """ super(IssueView, self).__init__(issue) # The users involved in this issue must be present in users_by_id if # this IssueView is to be used on the issue detail or peek pages. But, # they can be absent from users_by_id if the IssueView is used as a # tile in the grid view. self.owner = users_by_id.get(issue.owner_id) self.derived_owner = users_by_id.get(issue.derived_owner_id) self.cc = [users_by_id.get(cc_id) for cc_id in issue.cc_ids if cc_id] self.derived_cc = [ users_by_id.get(cc_id) for cc_id in issue.derived_cc_ids if cc_id ] self.status = framework_views.StatusView(issue.status, config) self.derived_status = framework_views.StatusView( issue.derived_status, config) # If we don't have a config available, we don't need to access is_open, so # let it be True. self.is_open = ezt.boolean( not config or tracker_helpers.MeansOpenInProject( tracker_bizobj.GetStatus(issue), config)) self.components = sorted([ ComponentValueView(component_id, config, False) for component_id in issue.component_ids if tracker_bizobj.FindComponentDefByID(component_id, config) ] + [ ComponentValueView(component_id, config, True) for component_id in issue.derived_component_ids if tracker_bizobj.FindComponentDefByID(component_id, config) ], key=lambda cvv: cvv.path) self.fields = MakeAllFieldValueViews(config, issue.labels, issue.derived_labels, issue.field_values, users_by_id) labels, derived_labels = tracker_bizobj.ExplicitAndDerivedNonMaskedLabels( issue, config) self.labels = [ framework_views.LabelView(label, config) for label in labels ] self.derived_labels = [ framework_views.LabelView(label, config) for label in derived_labels ] self.restrictions = _RestrictionsView(issue) # TODO(jrobbins): sort by order of labels in project config self.short_summary = issue.summary[:tracker_constants. SHORT_SUMMARY_LENGTH] if issue.closed_timestamp: self.closed = timestr.FormatAbsoluteDate(issue.closed_timestamp) else: self.closed = '' self.blocked_on = [] self.has_dangling = ezt.boolean(self.dangling_blocked_on_refs) self.blocking = [] self.detail_relative_url = tracker_helpers.FormatRelativeIssueURL( issue.project_name, urls.ISSUE_DETAIL, id=issue.local_id) self.crbug_url = tracker_helpers.FormatCrBugURL( issue.project_name, issue.local_id)
def __init__(self, project_name, comment_pb, users_by_id, autolink, all_referenced_artifacts, mr, issue, effective_ids=None): """Get IssueComment PB and make its fields available as attrs. Args: project_name: Name of the project this issue belongs to. comment_pb: Comment protocol buffer. users_by_id: dict mapping user_ids to UserViews, including the user that entered the comment, and any changed participants. autolink: utility object for automatically linking to other issues, git revisions, etc. all_referenced_artifacts: opaque object with details of referenced artifacts that is needed by autolink. mr: common information parsed from the HTTP request. issue: Issue PB for the issue that this comment is part of. effective_ids: optional set of int user IDs for the comment author. """ super(IssueCommentView, self).__init__(comment_pb) self.id = comment_pb.id self.creator = users_by_id[comment_pb.user_id] # TODO(jrobbins): this should be based on the issue project, not the # request project for non-project views and cross-project. if mr.project: self.creator_role = framework_helpers.GetRoleName( effective_ids or {self.creator.user_id}, mr.project) else: self.creator_role = None time_tuple = time.localtime(comment_pb.timestamp) self.date_string = timestr.FormatAbsoluteDate( comment_pb.timestamp, old_format=timestr.MONTH_DAY_YEAR_FMT) self.date_relative = timestr.FormatRelativeDate(comment_pb.timestamp) self.date_tooltip = time.asctime(time_tuple) self.date_yyyymmdd = timestr.FormatAbsoluteDate( comment_pb.timestamp, recent_format=timestr.MONTH_DAY_YEAR_FMT, old_format=timestr.MONTH_DAY_YEAR_FMT) self.text_runs = _ParseTextRuns(comment_pb.content) if autolink and not comment_pb.deleted_by: self.text_runs = autolink.MarkupAutolinks( mr, self.text_runs, all_referenced_artifacts) self.attachments = [ AttachmentView(attachment, project_name) for attachment in comment_pb.attachments ] self.amendments = sorted( [ AmendmentView(amendment, users_by_id, mr.project_name) for amendment in comment_pb.amendments ], key=lambda amendment: amendment.field_name.lower()) # Treat comments from banned users as being deleted. self.is_deleted = (comment_pb.deleted_by or (self.creator and self.creator.banned)) self.can_delete = False # TODO(jrobbins): pass through config to get granted permissions. perms = permissions.UpdateIssuePermissions(mr.perms, mr.project, issue, mr.auth.effective_ids) if mr.auth.user_id and mr.project: self.can_delete = permissions.CanDeleteComment( comment_pb, self.creator, mr.auth.user_id, perms) self.visible = permissions.CanViewComment(comment_pb, self.creator, mr.auth.user_id, perms)
def GetSortedHotlistIssues(mr, hotlist_issues, issues_list, harmonized_config, profiler, services): with profiler.Phase('Checking issue permissions and getting ranks'): allowed_issues = FilterIssues(mr, issues_list, services) allowed_iids = [issue.issue_id for issue in allowed_issues] # The values for issues in a hotlist are specific to the hotlist # (rank, adder, added) without invalidating the keys, an issue will retain # the rank value it has in one hotlist when navigating to another hotlist. sorting.InvalidateArtValuesKeys( mr.cnxn, [issue.issue_id for issue in allowed_issues]) sorted_ranks = sorted([ hotlist_issue.rank for hotlist_issue in hotlist_issues if hotlist_issue.issue_id in allowed_iids ]) friendly_ranks = { rank: friendly for friendly, rank in enumerate(sorted_ranks, 1) } issue_adders = framework_views.MakeAllUserViews( mr.cnxn, services.user, [hotlist_issue.adder_id for hotlist_issue in hotlist_issues]) hotlist_issues_context = { hotlist_issue.issue_id: { 'issue_rank': friendly_ranks[hotlist_issue.rank], 'adder_id': hotlist_issue.adder_id, 'date_added': timestr.FormatAbsoluteDate(hotlist_issue.date_added), 'note': hotlist_issue.note } for hotlist_issue in hotlist_issues if hotlist_issue.issue_id in allowed_iids } with profiler.Phase('Making user views'): issues_users_by_id = framework_views.MakeAllUserViews( mr.cnxn, services.user, tracker_bizobj.UsersInvolvedInIssues(allowed_issues or [])) issues_users_by_id.update(issue_adders) with profiler.Phase('Sorting issues'): sortable_fields = tracker_helpers.SORTABLE_FIELDS.copy() sortable_fields.update({ 'rank': lambda issue: hotlist_issues_context[issue.issue_id]['issue_rank'], 'adder': lambda issue: hotlist_issues_context[issue.issue_id]['adder_id'], 'added': lambda issue: hotlist_issues_context[issue.issue_id]['date_added'], 'note': lambda issue: hotlist_issues_context[issue.issue_id]['note'] }) sortable_postproc = tracker_helpers.SORTABLE_FIELDS_POSTPROCESSORS.copy( ) sortable_postproc.update({ 'adder': lambda user_view: user_view.email, }) if not mr.sort_spec: mr.sort_spec = 'rank' sorted_issues = sorting.SortArtifacts(mr, allowed_issues, harmonized_config, sortable_fields, sortable_postproc, users_by_id=issues_users_by_id, tie_breakers=['rank', 'id']) return sorted_issues, hotlist_issues_context, issues_users_by_id
def __init__( self, issue, users_by_id, config, open_related=None, closed_related=None, all_related=None): """Store relevant values for later display by EZT. Args: issue: An Issue protocol buffer. users_by_id: dict {user_id: UserViews} for all users mentioned in issue. config: ProjectIssueConfig for this issue. open_related: dict of visible open issues that are related to this issue. closed_related: dict {issue_id: issue} of visible closed issues that are related to this issue. all_related: dict {issue_id: issue} of all blocked-on, blocking, or merged-into issues referenced from this issue, regardless of perms. """ super(IssueView, self).__init__(issue) # The users involved in this issue must be present in users_by_id if # this IssueView is to be used on the issue detail or peek pages. But, # they can be absent from users_by_id if the IssueView is used as a # tile in the grid view. self.owner = users_by_id.get(issue.owner_id) self.derived_owner = users_by_id.get(issue.derived_owner_id) self.cc = [users_by_id.get(cc_id) for cc_id in issue.cc_ids if cc_id] self.derived_cc = [users_by_id.get(cc_id) for cc_id in issue.derived_cc_ids if cc_id] self.status = framework_views.StatusView(issue.status, config) self.derived_status = framework_views.StatusView( issue.derived_status, config) # If we don't have a config available, we don't need to access is_open, so # let it be True. self.is_open = ezt.boolean( not config or tracker_helpers.MeansOpenInProject( tracker_bizobj.GetStatus(issue), config)) self.components = sorted( [ComponentValueView(component_id, config, False) for component_id in issue.component_ids if tracker_bizobj.FindComponentDefByID(component_id, config)] + [ComponentValueView(component_id, config, True) for component_id in issue.derived_component_ids if tracker_bizobj.FindComponentDefByID(component_id, config)], key=lambda cvv: cvv.path) self.fields = [ MakeFieldValueView( fd, config, issue.labels, issue.derived_labels, issue.field_values, users_by_id) # TODO(jrobbins): field-level view restrictions, display options for fd in config.field_defs if not fd.is_deleted] self.fields = sorted( self.fields, key=lambda f: (f.applicable_type, f.field_name)) field_names = [fd.field_name.lower() for fd in config.field_defs if not fd.is_deleted] # TODO(jrobbins): restricts self.labels = [ framework_views.LabelView(label, config) for label in tracker_bizobj.NonMaskedLabels(issue.labels, field_names)] self.derived_labels = [ framework_views.LabelView(label, config) for label in issue.derived_labels if not tracker_bizobj.LabelIsMaskedByField(label, field_names)] self.restrictions = _RestrictionsView(issue) # TODO(jrobbins): sort by order of labels in project config self.short_summary = issue.summary[:tracker_constants.SHORT_SUMMARY_LENGTH] if issue.closed_timestamp: self.closed = timestr.FormatAbsoluteDate(issue.closed_timestamp) else: self.closed = '' blocked_on_iids = issue.blocked_on_iids blocking_iids = issue.blocking_iids # Note that merged_into_str and blocked_on_str includes all issue # references, even those referring to issues that the user can't view, # so open_related and closed_related cannot be used. if all_related is not None: all_blocked_on_refs = [ (all_related[ref_iid].project_name, all_related[ref_iid].local_id) for ref_iid in issue.blocked_on_iids] all_blocked_on_refs.extend([ (r.project, r.issue_id) for r in issue.dangling_blocked_on_refs]) self.blocked_on_str = ', '.join( tracker_bizobj.FormatIssueRef( ref, default_project_name=issue.project_name) for ref in all_blocked_on_refs) all_blocking_refs = [ (all_related[ref_iid].project_name, all_related[ref_iid].local_id) for ref_iid in issue.blocking_iids] all_blocking_refs.extend([ (r.project, r.issue_id) for r in issue.dangling_blocking_refs]) self.blocking_str = ', '.join( tracker_bizobj.FormatIssueRef( ref, default_project_name=issue.project_name) for ref in all_blocking_refs) if issue.merged_into: merged_issue = all_related[issue.merged_into] merged_into_ref = merged_issue.project_name, merged_issue.local_id else: merged_into_ref = None self.merged_into_str = tracker_bizobj.FormatIssueRef( merged_into_ref, default_project_name=issue.project_name) self.blocked_on = [] self.has_dangling = ezt.boolean(self.dangling_blocked_on_refs) self.blocking = [] current_project_name = issue.project_name if open_related is not None and closed_related is not None: self.merged_into = IssueRefView( current_project_name, issue.merged_into, open_related, closed_related) self.blocked_on = [ IssueRefView(current_project_name, iid, open_related, closed_related) for iid in blocked_on_iids] self.blocked_on.extend( [DanglingIssueRefView(ref.project, ref.issue_id) for ref in issue.dangling_blocked_on_refs]) self.blocked_on = [irv for irv in self.blocked_on if irv.visible] # TODO(jrobbins): sort by irv project_name and local_id self.blocking = [ IssueRefView(current_project_name, iid, open_related, closed_related) for iid in blocking_iids] self.blocking.extend( [DanglingIssueRefView(ref.project, ref.issue_id) for ref in issue.dangling_blocking_refs]) self.blocking = [irv for irv in self.blocking if irv.visible] # TODO(jrobbins): sort by irv project_name and local_id self.multiple_blocked_on = ezt.boolean(len(self.blocked_on) >= 2) self.detail_relative_url = tracker_helpers.FormatRelativeIssueURL( issue.project_name, urls.ISSUE_DETAIL, id=issue.local_id)
def GetDate(*args): date = datetime.datetime(*args) return timestr.FormatAbsoluteDate(calendar.timegm( date.utctimetuple()), clock=lambda: now)