papi-projects 0.1.4__tar.gz → 0.1.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {papi_projects-0.1.4 → papi_projects-0.1.6}/PKG-INFO +53 -1
- {papi_projects-0.1.4 → papi_projects-0.1.6}/README.md +52 -0
- papi_projects-0.1.6/papi/__init__.py +48 -0
- {papi_projects-0.1.4 → papi_projects-0.1.6}/papi/mocks.py +2 -0
- {papi_projects-0.1.4 → papi_projects-0.1.6}/papi/project.py +22 -12
- {papi_projects-0.1.4 → papi_projects-0.1.6}/papi/user.py +50 -4
- {papi_projects-0.1.4 → papi_projects-0.1.6}/papi/wrappers.py +416 -4
- {papi_projects-0.1.4 → papi_projects-0.1.6}/pyproject.toml +3 -1
- papi_projects-0.1.6/scripts/create_notion_project.py +82 -0
- papi_projects-0.1.6/scripts/create_project.py +143 -0
- {papi_projects-0.1.4 → papi_projects-0.1.6}/scripts/create_toggl_project.py +24 -14
- papi_projects-0.1.4/papi/__init__.py +0 -11
- {papi_projects-0.1.4 → papi_projects-0.1.6}/papi/tests/__init__.py +0 -0
- {papi_projects-0.1.4 → papi_projects-0.1.6}/papi/tests/test_project.py +0 -0
- {papi_projects-0.1.4 → papi_projects-0.1.6}/papi/tests/test_user.py +0 -0
- {papi_projects-0.1.4 → papi_projects-0.1.6}/papi/tests/test_userdb.json +0 -0
- {papi_projects-0.1.4 → papi_projects-0.1.6}/papi/tests/test_wrappers.py +0 -0
- {papi_projects-0.1.4 → papi_projects-0.1.6}/scripts/__init__.py +0 -0
- {papi_projects-0.1.4 → papi_projects-0.1.6}/scripts/collate_toggl_hours.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: papi-projects
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
4
4
|
Summary: PAPI is an API for managing projects
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: sandyjmacdonald
|
|
@@ -227,3 +227,55 @@ print(check_suffix("FZLL"))
|
|
|
227
227
|
print(check_suffix("1234"))
|
|
228
228
|
```
|
|
229
229
|
|
|
230
|
+
```
|
|
231
|
+
True
|
|
232
|
+
False
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## user module
|
|
236
|
+
|
|
237
|
+
## User class
|
|
238
|
+
|
|
239
|
+
The `User` class stores attributes of a user: their name, a three-letter initial (or two-letter initial and integer number from 1 to 9), and an optional email address.
|
|
240
|
+
|
|
241
|
+
The most basic way of instantiating a `User` instance is as follows:
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
from papi.user import User
|
|
245
|
+
|
|
246
|
+
usr = User("Charles Robert Darwin")
|
|
247
|
+
|
|
248
|
+
print(usr.user_id)
|
|
249
|
+
print(usr.user_name)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
CRD
|
|
254
|
+
Charles Robert Darwin
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
The first initials are converted into the `user_id` attribute.
|
|
258
|
+
|
|
259
|
+
If an email address is available, then this can be provided when instantiating:
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
from papi.user import User
|
|
263
|
+
|
|
264
|
+
usr = User("Charles Robert Darwin", email="cdarwin@beaglemail.com")
|
|
265
|
+
|
|
266
|
+
print(usr.email)
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
cdarwin@beaglemail.com
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Because our user ID naming scheme enforces that a user ID must be unique, the `user_id` attribute should not really be set directly, although it can in theory:
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
usr = User("Charles Darwin")
|
|
277
|
+
usr.user_id = "CD1"
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Setting the `user_id` attribute creates the possibility of a clash in user IDs, therefore the `user` module provides a means to create a basic user database with the TinyDB library. This avoids the possibility of a clash and appends and increments integer numbers to the end of the user ID if a matching one is already in the database.
|
|
281
|
+
|
|
@@ -208,3 +208,55 @@ from papi.project import check_suffix
|
|
|
208
208
|
print(check_suffix("FZLL"))
|
|
209
209
|
print(check_suffix("1234"))
|
|
210
210
|
```
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
True
|
|
214
|
+
False
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## user module
|
|
218
|
+
|
|
219
|
+
## User class
|
|
220
|
+
|
|
221
|
+
The `User` class stores attributes of a user: their name, a three-letter initial (or two-letter initial and integer number from 1 to 9), and an optional email address.
|
|
222
|
+
|
|
223
|
+
The most basic way of instantiating a `User` instance is as follows:
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
from papi.user import User
|
|
227
|
+
|
|
228
|
+
usr = User("Charles Robert Darwin")
|
|
229
|
+
|
|
230
|
+
print(usr.user_id)
|
|
231
|
+
print(usr.user_name)
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
CRD
|
|
236
|
+
Charles Robert Darwin
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
The first initials are converted into the `user_id` attribute.
|
|
240
|
+
|
|
241
|
+
If an email address is available, then this can be provided when instantiating:
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
from papi.user import User
|
|
245
|
+
|
|
246
|
+
usr = User("Charles Robert Darwin", email="cdarwin@beaglemail.com")
|
|
247
|
+
|
|
248
|
+
print(usr.email)
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
cdarwin@beaglemail.com
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Because our user ID naming scheme enforces that a user ID must be unique, the `user_id` attribute should not really be set directly, although it can in theory:
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
usr = User("Charles Darwin")
|
|
259
|
+
usr.user_id = "CD1"
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Setting the `user_id` attribute creates the possibility of a clash in user IDs, therefore the `user` module provides a means to create a basic user database with the TinyDB library. This avoids the possibility of a clash and appends and increments integer numbers to the end of the user ID if a matching one is already in the database.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import logging
|
|
3
|
+
from dotenv import dotenv_values
|
|
4
|
+
|
|
5
|
+
dotenv_path = os.path.join(os.path.dirname(__file__), '.env')
|
|
6
|
+
config = dotenv_values(dotenv_path)
|
|
7
|
+
|
|
8
|
+
ASANA_API_KEY = config["ASANA_API_KEY"]
|
|
9
|
+
ASANA_PASSWORD = config["ASANA_PASSWORD"]
|
|
10
|
+
|
|
11
|
+
TOGGL_TRACK_API_KEY = config["TOGGL_TRACK_API_KEY"]
|
|
12
|
+
TOGGL_TRACK_PASSWORD = config["TOGGL_TRACK_PASSWORD"]
|
|
13
|
+
|
|
14
|
+
NOTION_API_SECRET = config["NOTION_API_SECRET"]
|
|
15
|
+
NOTION_CLIENTS_DB = config["NOTION_CLIENTS_DB"]
|
|
16
|
+
NOTION_PROJECTS_DB = config["NOTION_PROJECTS_DB"]
|
|
17
|
+
|
|
18
|
+
def setup_logger(enable_logging: bool, log_level: str = 'INFO', log_file: str = None):
|
|
19
|
+
logger = logging.getLogger('papi')
|
|
20
|
+
|
|
21
|
+
if enable_logging:
|
|
22
|
+
# Convert log_level string to logging level
|
|
23
|
+
numeric_level = getattr(logging, log_level.upper(), logging.INFO)
|
|
24
|
+
logger.setLevel(numeric_level)
|
|
25
|
+
|
|
26
|
+
# Create handler
|
|
27
|
+
if log_file:
|
|
28
|
+
handler = logging.FileHandler(log_file)
|
|
29
|
+
else:
|
|
30
|
+
handler = logging.StreamHandler()
|
|
31
|
+
|
|
32
|
+
handler.setLevel(numeric_level)
|
|
33
|
+
|
|
34
|
+
# Create formatter
|
|
35
|
+
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
36
|
+
handler.setFormatter(formatter)
|
|
37
|
+
|
|
38
|
+
# Add handler to logger if not already added
|
|
39
|
+
if not logger.handlers:
|
|
40
|
+
logger.addHandler(handler)
|
|
41
|
+
|
|
42
|
+
# Prevent propagation to root logger
|
|
43
|
+
logger.propagate = False
|
|
44
|
+
else:
|
|
45
|
+
# Set a higher log level to suppress lower-level logs
|
|
46
|
+
logger.setLevel(logging.WARNING)
|
|
47
|
+
|
|
48
|
+
return logger
|
|
@@ -4,11 +4,13 @@ import random
|
|
|
4
4
|
import re
|
|
5
5
|
import uuid
|
|
6
6
|
import warnings
|
|
7
|
+
import logging
|
|
7
8
|
from typing import Protocol, runtime_checkable
|
|
8
9
|
from papi.user import check_user_id
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
11
12
|
|
|
13
|
+
THIS_YEAR = pendulum.now().year
|
|
12
14
|
|
|
13
15
|
def check_project_id(id: str) -> bool:
|
|
14
16
|
"""Checks whether a project ID is correctly formed.
|
|
@@ -18,10 +20,14 @@ def check_project_id(id: str) -> bool:
|
|
|
18
20
|
:return: True/False for whether project ID is correctly formed.
|
|
19
21
|
:rtype: bool
|
|
20
22
|
"""
|
|
23
|
+
logger.debug("Calling check_project_id function")
|
|
21
24
|
valid = False
|
|
22
25
|
pattern = re.compile(r"^P[0-9]{4}-[A-Z]{2}[A-Z1-9]{1}-[A-Z]{4}$")
|
|
23
26
|
if pattern.match(id):
|
|
24
27
|
valid = True
|
|
28
|
+
logger.info(f"Project ID '{id}' is valid")
|
|
29
|
+
else:
|
|
30
|
+
logger.info(f"Project ID '{id}' is not valid")
|
|
25
31
|
return valid
|
|
26
32
|
|
|
27
33
|
|
|
@@ -33,10 +39,14 @@ def check_suffix(suffix: str) -> bool:
|
|
|
33
39
|
:return: True/False for whether project suffix is correctly formed.
|
|
34
40
|
:rtype: bool
|
|
35
41
|
"""
|
|
42
|
+
logger.debug("Calling check_suffix function")
|
|
36
43
|
valid = False
|
|
37
44
|
pattern = re.compile(r"^[A-Z]{4}$")
|
|
38
45
|
if pattern.match(suffix):
|
|
39
46
|
valid = True
|
|
47
|
+
logger.info(f"Project suffix '{suffix}' is valid")
|
|
48
|
+
else:
|
|
49
|
+
logger.info(f"Project suffix '{suffix}' is not valid")
|
|
40
50
|
return valid
|
|
41
51
|
|
|
42
52
|
|
|
@@ -48,9 +58,12 @@ def check_uuid(p_uuid: str) -> bool:
|
|
|
48
58
|
:return: True/False for whether the UUID is valid.
|
|
49
59
|
:rtype: bool
|
|
50
60
|
"""
|
|
61
|
+
logger.debug("Calling check_uuid function")
|
|
51
62
|
try:
|
|
52
63
|
uuid_obj = uuid.UUID(p_uuid, version=4)
|
|
64
|
+
logger.info(f"Project UUID '{p_uuid}' is valid")
|
|
53
65
|
except ValueError:
|
|
66
|
+
logger.error(f"Project UUID '{p_uuid}' is not valid")
|
|
54
67
|
return False
|
|
55
68
|
return str(uuid_obj) == p_uuid
|
|
56
69
|
|
|
@@ -94,6 +107,7 @@ class Project(Protocol):
|
|
|
94
107
|
grant_code: str = None,
|
|
95
108
|
) -> None:
|
|
96
109
|
"""Constructor method"""
|
|
110
|
+
logger.debug("Creating Project instance")
|
|
97
111
|
self.year = year
|
|
98
112
|
self.user_id = user_id
|
|
99
113
|
self.grant_code = grant_code
|
|
@@ -126,22 +140,16 @@ class Project(Protocol):
|
|
|
126
140
|
)
|
|
127
141
|
else:
|
|
128
142
|
self.p_uuid = str(uuid.uuid4())
|
|
129
|
-
|
|
130
|
-
def __str__(self) -> str:
|
|
131
|
-
"""Human-readable representation of class. Currently just the project ID.
|
|
132
|
-
|
|
133
|
-
:return: Project ID.
|
|
134
|
-
:rtype: str
|
|
135
|
-
"""
|
|
136
|
-
return self.id
|
|
143
|
+
logger.info(f"Project '{self.id}' instance created")
|
|
137
144
|
|
|
138
145
|
def __repr__(self) -> str:
|
|
139
|
-
"""Machine-readable representation of class
|
|
146
|
+
"""Machine-readable representation of class..
|
|
140
147
|
|
|
141
|
-
:return: Project
|
|
148
|
+
:return: basic Project() attrs.
|
|
142
149
|
:rtype: str
|
|
143
150
|
"""
|
|
144
|
-
|
|
151
|
+
logger.debug("Calling Project.__repr__ method")
|
|
152
|
+
return f'Project("{self.id}", "{self.name}")'
|
|
145
153
|
|
|
146
154
|
def generate_suffix(self) -> str:
|
|
147
155
|
"""Generates a 4-character, uppercase, alphabetical suffix for a project, and
|
|
@@ -150,6 +158,7 @@ class Project(Protocol):
|
|
|
150
158
|
:return: Project suffix.
|
|
151
159
|
:rtype: str
|
|
152
160
|
"""
|
|
161
|
+
logger.debug("Calling Project.generate_suffix method")
|
|
153
162
|
letters = string.ascii_uppercase
|
|
154
163
|
suffix = "".join(random.choice(letters) for i in range(4))
|
|
155
164
|
self.suffix = suffix
|
|
@@ -161,4 +170,5 @@ class Project(Protocol):
|
|
|
161
170
|
:return: True/False for whether the project ID is valid.
|
|
162
171
|
:rtype: bool
|
|
163
172
|
"""
|
|
173
|
+
logger.debug("Calling Project.id_is_valid method")
|
|
164
174
|
return check_project_id(self.id)
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import re
|
|
2
2
|
import pendulum
|
|
3
|
+
import logging
|
|
3
4
|
from typing import Protocol, runtime_checkable
|
|
4
5
|
from tinydb import TinyDB, Query
|
|
5
6
|
from tinydb.operations import *
|
|
6
7
|
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
7
9
|
|
|
8
10
|
def user_name_to_user_id(user_name: str) -> str:
|
|
9
11
|
"""Generates a 3-character, uppercase, alphabetical user ID from a user name,
|
|
@@ -14,8 +16,10 @@ def user_name_to_user_id(user_name: str) -> str:
|
|
|
14
16
|
:return: Three-character user ID.
|
|
15
17
|
:rtype: str
|
|
16
18
|
"""
|
|
19
|
+
logger.debug("Calling user_name_to_user_id function")
|
|
17
20
|
user_name_parts = user_name.split()
|
|
18
21
|
user_id = "".join([word[0] for word in user_name_parts]).upper()
|
|
22
|
+
logger.info(f"User name '{user_name}' converted to user ID '{user_id}'")
|
|
19
23
|
return user_id
|
|
20
24
|
|
|
21
25
|
|
|
@@ -28,8 +32,13 @@ def check_valid_email(email: str) -> bool:
|
|
|
28
32
|
:return: True/False for whether the email is valid.
|
|
29
33
|
:rtype: bool
|
|
30
34
|
"""
|
|
35
|
+
logger.debug("Calling check_valid_email function")
|
|
31
36
|
valid_email = re.compile(r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
|
|
32
37
|
valid = valid_email.match(email)
|
|
38
|
+
if valid:
|
|
39
|
+
logger.info(f"Email '{email}' is valid")
|
|
40
|
+
else:
|
|
41
|
+
logger.warning(f"Email '{email}' is not valid")
|
|
33
42
|
return valid
|
|
34
43
|
|
|
35
44
|
|
|
@@ -43,13 +52,16 @@ def check_user_id(user_id: str) -> bool:
|
|
|
43
52
|
:return: True/False for whether the user ID is valid.
|
|
44
53
|
:rtype: bool
|
|
45
54
|
"""
|
|
55
|
+
logger.debug("Calling check_user_id function")
|
|
46
56
|
if not isinstance(user_id, str):
|
|
57
|
+
logger.warning(f"User ID '{user_id}' is not valid")
|
|
47
58
|
return False
|
|
48
59
|
else:
|
|
49
60
|
valid = False
|
|
50
61
|
pattern = re.compile(r"^[A-Z]{2}[A-Z0-9]{1}$")
|
|
51
62
|
if pattern.match(user_id):
|
|
52
63
|
valid = True
|
|
64
|
+
logger.info(f"User ID '{user_id}' is valid")
|
|
53
65
|
return valid
|
|
54
66
|
|
|
55
67
|
|
|
@@ -60,6 +72,8 @@ class User(Protocol):
|
|
|
60
72
|
|
|
61
73
|
:param user_name: User name, e.g. John Smith.
|
|
62
74
|
:type user_name: str
|
|
75
|
+
:param user_id: User ID, e.g. JS1.
|
|
76
|
+
:type user_id: str
|
|
63
77
|
:param email: Email address, defaults to None.
|
|
64
78
|
:type email: str, optional
|
|
65
79
|
:raises ValueError: If the name does not consist of either 2 or 3 parts, then
|
|
@@ -68,10 +82,12 @@ class User(Protocol):
|
|
|
68
82
|
ValueError is raised.
|
|
69
83
|
"""
|
|
70
84
|
|
|
71
|
-
def __init__(self, user_name: str, email: str = None):
|
|
85
|
+
def __init__(self, user_name: str = None, user_id: str = None, email: str = None):
|
|
72
86
|
"""Constructor method"""
|
|
73
|
-
|
|
74
|
-
|
|
87
|
+
logger.debug("Creating User instance")
|
|
88
|
+
if user_name is not None:
|
|
89
|
+
if len(user_name.split()) == 0 or len(user_name.split()) > 3:
|
|
90
|
+
raise ValueError("Name must consist of one to three parts only")
|
|
75
91
|
self.user_name = user_name
|
|
76
92
|
if email is not None:
|
|
77
93
|
valid_email = check_valid_email(email)
|
|
@@ -80,8 +96,12 @@ class User(Protocol):
|
|
|
80
96
|
self.email = email
|
|
81
97
|
else:
|
|
82
98
|
self.email = ""
|
|
83
|
-
|
|
99
|
+
if user_id is None:
|
|
100
|
+
self.user_id = user_name_to_user_id(user_name)
|
|
101
|
+
else:
|
|
102
|
+
self.user_id = user_id
|
|
84
103
|
self.created_at = str(pendulum.now())
|
|
104
|
+
logger.info(f"User '{self.user_id}' instance created")
|
|
85
105
|
|
|
86
106
|
def to_json(self):
|
|
87
107
|
"""Returns a user in JSON (dictionary) form.
|
|
@@ -89,12 +109,22 @@ class User(Protocol):
|
|
|
89
109
|
:return: JSON-formatted (i.e. dictionary) user.
|
|
90
110
|
:rtype: dict
|
|
91
111
|
"""
|
|
112
|
+
logger.debug("Calling User.to_json method")
|
|
92
113
|
return {
|
|
93
114
|
"user_name": self.user_name,
|
|
94
115
|
"user_id": self.user_id,
|
|
95
116
|
"email": self.email,
|
|
96
117
|
"created_at": self.created_at,
|
|
97
118
|
}
|
|
119
|
+
|
|
120
|
+
def __repr__(self):
|
|
121
|
+
"""Machine-readable representation of class.
|
|
122
|
+
|
|
123
|
+
:return: basic User() attrs.
|
|
124
|
+
:rtype: str
|
|
125
|
+
"""
|
|
126
|
+
logger.debug("Calling User.__repr__ method")
|
|
127
|
+
return f'User("{self.user_name}", "{self.user_id}", {self.email})'
|
|
98
128
|
|
|
99
129
|
|
|
100
130
|
@runtime_checkable
|
|
@@ -110,6 +140,7 @@ class UserDB(Protocol):
|
|
|
110
140
|
|
|
111
141
|
def __init__(self, db_file: str = None) -> None:
|
|
112
142
|
"""Constructor method"""
|
|
143
|
+
logger.debug("Creating UserDB instance")
|
|
113
144
|
if db_file is not None:
|
|
114
145
|
self.db = TinyDB(db_file, sort_keys=True, indent=4, separators=(",", ": "))
|
|
115
146
|
self.db_file = db_file
|
|
@@ -118,6 +149,8 @@ class UserDB(Protocol):
|
|
|
118
149
|
self.db = TinyDB(
|
|
119
150
|
self.db_file, sort_keys=True, indent=4, separators=(",", ": ")
|
|
120
151
|
)
|
|
152
|
+
logger.info(f"UserDB '{self.db_file}' instance created")
|
|
153
|
+
|
|
121
154
|
|
|
122
155
|
def insert_user(self, user) -> User:
|
|
123
156
|
"""Inserts a user into the database, using a User instance.
|
|
@@ -128,6 +161,7 @@ class UserDB(Protocol):
|
|
|
128
161
|
:return: ID of the inserted user.
|
|
129
162
|
:rtype: int
|
|
130
163
|
"""
|
|
164
|
+
logger.debug("Calling UserDB.insert_user method")
|
|
131
165
|
if len(user.user_name.split()) == 2:
|
|
132
166
|
matches = self.check_matching_user_ids(user.user_id)
|
|
133
167
|
if len(matches):
|
|
@@ -150,6 +184,7 @@ class UserDB(Protocol):
|
|
|
150
184
|
else:
|
|
151
185
|
user.user_id = f"{first_last_initial}1"
|
|
152
186
|
self.db.insert(user.to_json())
|
|
187
|
+
logger.info(f"User ID '{useruser_id}' inserted into user database")
|
|
153
188
|
return user.user_id
|
|
154
189
|
|
|
155
190
|
def search_by_user_name(self, user_name: str) -> list:
|
|
@@ -161,8 +196,13 @@ class UserDB(Protocol):
|
|
|
161
196
|
:return: A list of matching documents.
|
|
162
197
|
:rtype: list
|
|
163
198
|
"""
|
|
199
|
+
logger.debug("Calling UserDB.search_by_user_name method")
|
|
164
200
|
Users = Query()
|
|
165
201
|
result = self.db.search(Users.user_name == user_name)
|
|
202
|
+
if len(result):
|
|
203
|
+
logger.info(f"{len(result)} matches for {user_name} found in user database")
|
|
204
|
+
else:
|
|
205
|
+
logger.info(f"No matches for {user_name} found in user database")
|
|
166
206
|
return result
|
|
167
207
|
|
|
168
208
|
def search_by_user_id(self, user_id: str) -> list:
|
|
@@ -174,8 +214,13 @@ class UserDB(Protocol):
|
|
|
174
214
|
:return: A list of matching documents.
|
|
175
215
|
:rtype: list
|
|
176
216
|
"""
|
|
217
|
+
logger.debug("Calling UserDB.search_by_user_id method")
|
|
177
218
|
Users = Query()
|
|
178
219
|
result = self.db.search(Users.user_id == user_id)
|
|
220
|
+
if len(result):
|
|
221
|
+
logger.info(f"{len(result)} matches for {user_id} found in user database")
|
|
222
|
+
else:
|
|
223
|
+
logger.info(f"No matches for {user_id} found in user database")
|
|
179
224
|
return result
|
|
180
225
|
|
|
181
226
|
def check_matching_user_ids(self, user_id: str) -> list:
|
|
@@ -189,6 +234,7 @@ class UserDB(Protocol):
|
|
|
189
234
|
:return: A list of matching documents.
|
|
190
235
|
:rtype: list
|
|
191
236
|
"""
|
|
237
|
+
logger.debug("Calling UserDB.check_matching_user_ids method")
|
|
192
238
|
Users = Query()
|
|
193
239
|
if user_id[-1].isnumeric() or len(user_id) == 2:
|
|
194
240
|
result = self.db.search(Users.user_id.search(rf"^{user_id[0:2]}\d{{1}}"))
|