blob: 804e6a492872e6d846081ec9fc7aa1bb7d48ff59 [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001# Copyright 2016 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style
3# license that can be found in the LICENSE file or at
4# https://developers.google.com/open-source/licenses/bsd
5
6"""Business objects for the Monorail features.
7
8These are classes and functions that operate on the objects that users care
9about in features (eg. hotlists).
10"""
11from __future__ import print_function
12from __future__ import division
13from __future__ import absolute_import
14
15import logging
16
17from framework import framework_bizobj
18from framework import urls
19from proto import features_pb2
20
21
22def GetOwnerIds(hotlist):
23 """Returns the list of ids for the given hotlist's owners."""
24 return hotlist.owner_ids
25
26
27def UsersInvolvedInHotlists(hotlists):
28 """Returns a set of all users who have roles in the given hotlists."""
29 result = set()
30 for hotlist in hotlists:
31 result.update(hotlist.owner_ids)
32 result.update(hotlist.editor_ids)
33 result.update(hotlist.follower_ids)
34 return result
35
36
37def UserOwnsHotlist(hotlist, effective_ids):
38 """Returns T/F if the user is the owner/not the owner of the hotlist."""
39 return not effective_ids.isdisjoint(hotlist.owner_ids or set())
40
41
42def IssueIsInHotlist(hotlist, issue_id):
43 """Returns T/F if the issue is in the hotlist."""
44 return any(issue_id == hotlist_issue.issue_id
45 for hotlist_issue in hotlist.items)
46
47
48def UserIsInHotlist(hotlist, effective_ids):
49 """Returns T/F if the user is involved/not involved in the hotlist."""
50 return (UserOwnsHotlist(hotlist, effective_ids) or
51 not effective_ids.isdisjoint(hotlist.editor_ids or set()) or
52 not effective_ids.isdisjoint(hotlist.follower_ids or set()))
53
54
55def SplitHotlistIssueRanks(target_iid, split_above, iid_rank_pairs):
56 """Splits hotlist issue relation rankings by some target issue's rank.
57
58 Hotlists issues are sorted Low to High. When split_above is true,
59 the split should occur before the target object and the objects
60 should be moved above the target, with lower ranks than the target.
61
62 Args:
63 target_iid: the global ID of the issue to split rankings about.
64 split_above: False to split below the target issue, True to split above.
65 iid_rank_pairs: a list tuples [(issue_id, rank_in_hotlist),...} for all
66 issues in a hotlist excluding the one being moved.
67
68 Returns:
69 A tuple (lower, higher) where both are lists of [(issue_iid, rank), ...]
70 of issues in rank order. If split_above is False the target issue is
71 included in higher, otherwise it is included in lower.
72 """
73 iid_rank_pairs.reverse()
74 offset = int(not split_above)
75 for i, (issue_id, _) in enumerate(iid_rank_pairs):
76 if issue_id == target_iid:
77 return iid_rank_pairs[:i + offset], iid_rank_pairs[i + offset:]
78 logging.error(
79 'Target issue %r was not found in the list of issue_id rank pairs',
80 target_iid)
81 return iid_rank_pairs, []
82
83
84def DetermineHotlistIssuePosition(issue, issue_ids):
85 """Find position of an issue in a hotlist for a flipper.
86
87 Args:
88 issue: The issue PB currently being viewed
89 issue_ids: list of issue_id's
90
91 Returns:
92 A 3-tuple (prev_iid, index, next_iid) where prev_iid is the
93 IID of the previous issue in the total ordering (or None),
94 index is the index that the current issue has in the sorted
95 list of issues in the hotlist,
96 next_iid is the next issue (or None).
97 """
98
99 prev_iid, next_iid = None, None
100 total_issues = len(issue_ids)
101 for i, issue_id in enumerate(issue_ids):
102 if issue_id == issue.issue_id:
103 index = i
104 if i < total_issues - 1:
105 next_iid = issue_ids[i + 1]
106 if i > 0:
107 prev_iid = issue_ids[i - 1]
108 return prev_iid, index, next_iid
109 return None, None, None