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