Coverage for rfpy/api/endpoints/notes.py: 100%
65 statements
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-31 16:00 +0000
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-31 16:00 +0000
1'''
2Manage Project Notes - messages between participants and respondents in a project.
3'''
4from typing import List
6from sqlalchemy.orm import Session
8from rfpy.model import ProjectNote, AuditEvent
9from rfpy.model.humans import User
10from rfpy.suxint import http
11from rfpy.web import serial
12from rfpy.api import fetch, validate
13from rfpy.auth import perms
16@http
17def get_project_notes(session, user, project_id) -> List[serial.ReadNote]:
18 '''
19 Get a list of ProjectNotes for the given project_id.
21 @raise AuthorisationFailue - if the user is not a standard user from the buying organisation
22 @raise NoResultFound - if the specified project cannot be loaded
23 '''
24 project = fetch.project(session, project_id)
25 validate.check(user, perms.PROJECT_ACCESS, project=project)
26 return [serial.ReadNote.from_orm(pn) for pn in fetch.participant_notes_query(project)]
29def issue_if_target_set(project, note):
30 if not note.target_org_id:
31 return None
33 issue = project._issues.filter_by(respondent_id=note.target_org_id).first()
34 if issue is None:
35 m = f"Org '{note.target_org_id}'' is not a respondent in project {project.id}"
36 raise ValueError(m)
37 return issue
40@http
41def post_project_note(session: Session,
42 user: User,
43 project_id: int,
44 note_doc: serial.ProjectNote) -> serial.Id:
45 '''
46 Add a Note to the given Project
48 The visibility of Notes to different organisation is given by the table below - the last three
49 columns indicate the visiblity of the message to each group.
51 |private|target_org_id defined|all respondents? |target respondent?|participants? |
52 |-------|---------------------|-----------------|------------------|----------------|
53 |false | true | no | yes | yes |
54 |false | false | yes | not applicable | yes |
55 |true | false | yes | not applicable | yes |
56 |true | true | no | no | yes |
59 Field 'target_org_id' is the ID of the Organisation to whom a Note is addressed. The
60 Organisation must be a respondent for the current Project
61 (i.e assigned as Respondent for an Issue).
63 Setting 'target_org_id' has no effect if the message is private (in which case only users in
64 Particpant organisations can view the message)
66 @permissions PROJECT_ADD_NOTE
67 '''
68 project = fetch.project(session, project_id)
69 validate.check(user, perms.PROJECT_ADD_NOTE, project=project)
70 note = ProjectNote(kind='IssuerNote',
71 project_id=project_id,
72 note_text=note_doc['note_text'],
73 private=note_doc['private'],
74 user_id=user.id,
75 org_id=user.org_id)
76 issue = None
77 target_id = note_doc.get('target_org_id', None)
78 if target_id is not None and target_id.strip() != '':
79 note.target_org_id = note_doc['target_org_id']
80 issue = issue_if_target_set(project, note)
82 session.add(note)
83 session.flush()
84 evt = AuditEvent.create('PROJECT_NOTE_ADDED',
85 project=project,
86 object_id=note.id,
87 user_id=user.id,
88 org_id=user.org_id,
89 issue=issue)
90 evt.add_change('note_text', '', note.note_text)
91 evt.add_change('private', '', note.private)
92 evt.add_change('target_org_id', '', note.target_org_id)
93 session.add(evt)
94 return {'id': note.id}
97@http
98def put_project_note(session: Session, user, project_id, note_id, note_doc):
99 '''
100 Update a Project Note. See Post Project Note for details of privacy and visibility
102 @permissions PROJECT_ADD_NOTE
103 '''
104 project = fetch.project(session, project_id)
105 validate.check(user, perms.PROJECT_ADD_NOTE, project=project)
106 note = fetch.note(project, note_id)
107 issue = issue_if_target_set(project, note)
108 print('issue', issue)
109 if issue is not None:
110 evt = AuditEvent.create('PROJECT_NOTE_UPDATED',
111 project=project,
112 object_id=note.id,
113 user_id=user.id,
114 org_id=user.org_id,
115 issue=issue)
116 else:
117 evt = AuditEvent.create('PROJECT_NOTE_UPDATED',
118 project=project,
119 object_id=note.id,
120 user_id=user.id,
121 org_id=user.org_id)
122 for k in ('note_text', 'private', 'target_org_id'):
123 if note_doc.get(k, None):
124 if note_doc[k] != getattr(note, k):
125 evt.add_change(k, getattr(note, k), note_doc[k])
126 setattr(note, k, note_doc[k])
128 session.add(evt)
131@http
132def delete_project_note(session: Session, user, project_id, note_id):
133 '''
134 Delete a Project Note
136 @permissions PROJECT_ADD_NOTE
137 '''
138 project = fetch.project(session, project_id)
139 validate.check(user, perms.PROJECT_ADD_NOTE, project=project)
140 note = fetch.note(project, note_id)
142 issue = issue_if_target_set(project, note)
143 evt = AuditEvent.create('PROJECT_NOTE_DELETED',
144 project=project,
145 object_id=note.id,
146 user_id=user.id,
147 org_id=user.org_id,
148 issue=issue)
149 session.add(evt)
150 session.flush()
151 session.delete(note)