projectal.entities.timelog
1import projectal 2from projectal.entity import Entity 3from projectal.linkers import * 4from projectal import api 5 6 7class Timelog( 8 Entity, 9 FileLinker, 10 NoteLinker, 11 TagLinker, 12): 13 """ 14 Implementation of the [Timelog](https://projectal.com/docs/latest/#tag/Timelog) API. 15 """ 16 17 _path = "timelog" 18 _name = "timelog" 19 20 _links = [ 21 FileLinker, 22 NoteLinker, 23 TagLinker, 24 ] 25 26 @classmethod 27 def create( 28 cls, 29 holder, 30 entities, 31 batch_linking=True, 32 disable_system_features=True, 33 enable_system_features_on_exit=True, 34 ): 35 """Create a Timelog 36 37 `holder`: An instance or the `uuId` of the Staff 38 39 `entities`: `dict` containing the fields of the entity to be created, 40 or a list of such `dict`s to create in bulk. 41 """ 42 holder_id = holder["uuId"] if isinstance(holder, dict) else holder 43 params = "?holder=" + holder_id 44 out = super().create( 45 entities, 46 params, 47 batch_linking, 48 disable_system_features, 49 enable_system_features_on_exit, 50 ) 51 52 # Timelogs should always refer to their Staff. We don't get this information from the 53 # creation api method, but we can insert them ourselves because we know what they are. 54 def add_fields(obj): 55 obj.set_readonly("staffRef", holder_id) 56 57 if isinstance(out, dict): 58 add_fields(out) 59 if isinstance(out, list): 60 for obj in out: 61 add_fields(obj) 62 return out 63 64 @classmethod 65 def list(cls, expand=False, links=None): 66 """Return a list of all entity UUIDs of this type. 67 68 You may pass in `expand=True` to get full Entity objects 69 instead, but be aware this may be very slow if you have 70 thousands of objects. 71 72 If you are expanding the objects, you may further expand 73 the results with `links`. 74 """ 75 76 payload = { 77 "name": "List all entities of type {}".format(cls._name.upper()), 78 "type": "msql", 79 "start": 0, 80 "limit": -1, 81 "select": [["STAFF.{}.uuId".format(cls._name.upper())]], 82 } 83 ids = api.query(payload) 84 ids = [id[0] for id in ids] 85 if ids: 86 return cls.get(ids, links=links) if expand else ids 87 return [] 88 89 @classmethod 90 def match(cls, field, term, links=None): 91 """Find entities where `field`=`term` (exact match), optionally 92 expanding the results with `links`. 93 94 Relies on `Entity.query()` with a pre-built set of rules. 95 ``` 96 projects = projectal.Project.match('identifier', 'zmb-005') 97 ``` 98 """ 99 filter = [["STAFF.{}.{}".format(cls._name.upper(), field), "eq", term]] 100 return cls.query(filter, links) 101 102 @classmethod 103 def match_startswith(cls, field, term, links=None): 104 """Find entities where `field` starts with the text `term`, 105 optionally expanding the results with `links`. 106 107 Relies on `Entity.query()` with a pre-built set of rules. 108 ``` 109 projects = projectal.Project.match_startswith('name', 'Zomb') 110 ``` 111 """ 112 filter = [["STAFF.{}.{}".format(cls._name.upper(), field), "prefix", term]] 113 return cls.query(filter, links) 114 115 @classmethod 116 def match_endswith(cls, field, term, links=None): 117 """Find entities where `field` ends with the text `term`, 118 optionally expanding the results with `links`. 119 120 Relies on `Entity.query()` with a pre-built set of rules. 121 ``` 122 projects = projectal.Project.match_endswith('identifier', '-2023') 123 ``` 124 """ 125 term = "(?i).*{}$".format(term) 126 filter = [["STAFF.{}.{}".format(cls._name.upper(), field), "regex", term]] 127 return cls.query(filter, links) 128 129 @classmethod 130 def search(cls, fields=None, term="", case_sensitive=True, links=None): 131 """Find entities that contain the text `term` within `fields`. 132 `fields` is a list of field names to target in the search. 133 134 `case_sensitive`: Optionally turn off case sensitivity in the search. 135 136 Relies on `Entity.query()` with a pre-built set of rules. 137 ``` 138 projects = projectal.Project.search(['name', 'description'], 'zombie') 139 ``` 140 """ 141 filter = [] 142 term = "(?{}).*{}.*".format("" if case_sensitive else "?", term) 143 for field in fields: 144 filter.append( 145 ["STAFF.{}.{}".format(cls._name.upper(), field), "regex", term] 146 ) 147 filter = ["_or_", filter] 148 return cls.query(filter, links) 149 150 @classmethod 151 def query(cls, filter, links=None, timeout=30): 152 """Run a query on this entity with the supplied filter. 153 154 The query is already set up to target this entity type, and the 155 results will be converted into full objects when found, optionally 156 expanded with the `links` provided. You only need to supply a 157 filter to reduce the result set. 158 159 See [the filter documentation](https://projectal.com/docs/v1.1.1#section/Filter-section) 160 for a detailed overview of the kinds of filters you can construct. 161 """ 162 ids = [] 163 request_completed = False 164 limit = projectal.query_chunk_size 165 start = 0 166 while not request_completed: 167 payload = { 168 "name": "Python library entity query ({})".format(cls._name.upper()), 169 "type": "msql", 170 "start": start, 171 "limit": limit, 172 "select": [["STAFF.{}.uuId".format(cls._name.upper())]], 173 "filter": filter, 174 "timeout": timeout, 175 } 176 result = projectal.query(payload) 177 ids.extend(result) 178 if len(result) < limit: 179 request_completed = True 180 else: 181 start += limit 182 183 ids = [id[0] for id in ids] 184 if ids: 185 return cls.get(ids, links=links) 186 return []
8class Timelog( 9 Entity, 10 FileLinker, 11 NoteLinker, 12 TagLinker, 13): 14 """ 15 Implementation of the [Timelog](https://projectal.com/docs/latest/#tag/Timelog) API. 16 """ 17 18 _path = "timelog" 19 _name = "timelog" 20 21 _links = [ 22 FileLinker, 23 NoteLinker, 24 TagLinker, 25 ] 26 27 @classmethod 28 def create( 29 cls, 30 holder, 31 entities, 32 batch_linking=True, 33 disable_system_features=True, 34 enable_system_features_on_exit=True, 35 ): 36 """Create a Timelog 37 38 `holder`: An instance or the `uuId` of the Staff 39 40 `entities`: `dict` containing the fields of the entity to be created, 41 or a list of such `dict`s to create in bulk. 42 """ 43 holder_id = holder["uuId"] if isinstance(holder, dict) else holder 44 params = "?holder=" + holder_id 45 out = super().create( 46 entities, 47 params, 48 batch_linking, 49 disable_system_features, 50 enable_system_features_on_exit, 51 ) 52 53 # Timelogs should always refer to their Staff. We don't get this information from the 54 # creation api method, but we can insert them ourselves because we know what they are. 55 def add_fields(obj): 56 obj.set_readonly("staffRef", holder_id) 57 58 if isinstance(out, dict): 59 add_fields(out) 60 if isinstance(out, list): 61 for obj in out: 62 add_fields(obj) 63 return out 64 65 @classmethod 66 def list(cls, expand=False, links=None): 67 """Return a list of all entity UUIDs of this type. 68 69 You may pass in `expand=True` to get full Entity objects 70 instead, but be aware this may be very slow if you have 71 thousands of objects. 72 73 If you are expanding the objects, you may further expand 74 the results with `links`. 75 """ 76 77 payload = { 78 "name": "List all entities of type {}".format(cls._name.upper()), 79 "type": "msql", 80 "start": 0, 81 "limit": -1, 82 "select": [["STAFF.{}.uuId".format(cls._name.upper())]], 83 } 84 ids = api.query(payload) 85 ids = [id[0] for id in ids] 86 if ids: 87 return cls.get(ids, links=links) if expand else ids 88 return [] 89 90 @classmethod 91 def match(cls, field, term, links=None): 92 """Find entities where `field`=`term` (exact match), optionally 93 expanding the results with `links`. 94 95 Relies on `Entity.query()` with a pre-built set of rules. 96 ``` 97 projects = projectal.Project.match('identifier', 'zmb-005') 98 ``` 99 """ 100 filter = [["STAFF.{}.{}".format(cls._name.upper(), field), "eq", term]] 101 return cls.query(filter, links) 102 103 @classmethod 104 def match_startswith(cls, field, term, links=None): 105 """Find entities where `field` starts with the text `term`, 106 optionally expanding the results with `links`. 107 108 Relies on `Entity.query()` with a pre-built set of rules. 109 ``` 110 projects = projectal.Project.match_startswith('name', 'Zomb') 111 ``` 112 """ 113 filter = [["STAFF.{}.{}".format(cls._name.upper(), field), "prefix", term]] 114 return cls.query(filter, links) 115 116 @classmethod 117 def match_endswith(cls, field, term, links=None): 118 """Find entities where `field` ends with the text `term`, 119 optionally expanding the results with `links`. 120 121 Relies on `Entity.query()` with a pre-built set of rules. 122 ``` 123 projects = projectal.Project.match_endswith('identifier', '-2023') 124 ``` 125 """ 126 term = "(?i).*{}$".format(term) 127 filter = [["STAFF.{}.{}".format(cls._name.upper(), field), "regex", term]] 128 return cls.query(filter, links) 129 130 @classmethod 131 def search(cls, fields=None, term="", case_sensitive=True, links=None): 132 """Find entities that contain the text `term` within `fields`. 133 `fields` is a list of field names to target in the search. 134 135 `case_sensitive`: Optionally turn off case sensitivity in the search. 136 137 Relies on `Entity.query()` with a pre-built set of rules. 138 ``` 139 projects = projectal.Project.search(['name', 'description'], 'zombie') 140 ``` 141 """ 142 filter = [] 143 term = "(?{}).*{}.*".format("" if case_sensitive else "?", term) 144 for field in fields: 145 filter.append( 146 ["STAFF.{}.{}".format(cls._name.upper(), field), "regex", term] 147 ) 148 filter = ["_or_", filter] 149 return cls.query(filter, links) 150 151 @classmethod 152 def query(cls, filter, links=None, timeout=30): 153 """Run a query on this entity with the supplied filter. 154 155 The query is already set up to target this entity type, and the 156 results will be converted into full objects when found, optionally 157 expanded with the `links` provided. You only need to supply a 158 filter to reduce the result set. 159 160 See [the filter documentation](https://projectal.com/docs/v1.1.1#section/Filter-section) 161 for a detailed overview of the kinds of filters you can construct. 162 """ 163 ids = [] 164 request_completed = False 165 limit = projectal.query_chunk_size 166 start = 0 167 while not request_completed: 168 payload = { 169 "name": "Python library entity query ({})".format(cls._name.upper()), 170 "type": "msql", 171 "start": start, 172 "limit": limit, 173 "select": [["STAFF.{}.uuId".format(cls._name.upper())]], 174 "filter": filter, 175 "timeout": timeout, 176 } 177 result = projectal.query(payload) 178 ids.extend(result) 179 if len(result) < limit: 180 request_completed = True 181 else: 182 start += limit 183 184 ids = [id[0] for id in ids] 185 if ids: 186 return cls.get(ids, links=links) 187 return []
Implementation of the Timelog API.
27 @classmethod 28 def create( 29 cls, 30 holder, 31 entities, 32 batch_linking=True, 33 disable_system_features=True, 34 enable_system_features_on_exit=True, 35 ): 36 """Create a Timelog 37 38 `holder`: An instance or the `uuId` of the Staff 39 40 `entities`: `dict` containing the fields of the entity to be created, 41 or a list of such `dict`s to create in bulk. 42 """ 43 holder_id = holder["uuId"] if isinstance(holder, dict) else holder 44 params = "?holder=" + holder_id 45 out = super().create( 46 entities, 47 params, 48 batch_linking, 49 disable_system_features, 50 enable_system_features_on_exit, 51 ) 52 53 # Timelogs should always refer to their Staff. We don't get this information from the 54 # creation api method, but we can insert them ourselves because we know what they are. 55 def add_fields(obj): 56 obj.set_readonly("staffRef", holder_id) 57 58 if isinstance(out, dict): 59 add_fields(out) 60 if isinstance(out, list): 61 for obj in out: 62 add_fields(obj) 63 return out
Create a Timelog
holder: An instance or the uuId of the Staff
entities: dict containing the fields of the entity to be created,
or a list of such dicts to create in bulk.
65 @classmethod 66 def list(cls, expand=False, links=None): 67 """Return a list of all entity UUIDs of this type. 68 69 You may pass in `expand=True` to get full Entity objects 70 instead, but be aware this may be very slow if you have 71 thousands of objects. 72 73 If you are expanding the objects, you may further expand 74 the results with `links`. 75 """ 76 77 payload = { 78 "name": "List all entities of type {}".format(cls._name.upper()), 79 "type": "msql", 80 "start": 0, 81 "limit": -1, 82 "select": [["STAFF.{}.uuId".format(cls._name.upper())]], 83 } 84 ids = api.query(payload) 85 ids = [id[0] for id in ids] 86 if ids: 87 return cls.get(ids, links=links) if expand else ids 88 return []
Return a list of all entity UUIDs of this type.
You may pass in expand=True to get full Entity objects
instead, but be aware this may be very slow if you have
thousands of objects.
If you are expanding the objects, you may further expand
the results with links.
90 @classmethod 91 def match(cls, field, term, links=None): 92 """Find entities where `field`=`term` (exact match), optionally 93 expanding the results with `links`. 94 95 Relies on `Entity.query()` with a pre-built set of rules. 96 ``` 97 projects = projectal.Project.match('identifier', 'zmb-005') 98 ``` 99 """ 100 filter = [["STAFF.{}.{}".format(cls._name.upper(), field), "eq", term]] 101 return cls.query(filter, links)
Find entities where field=term (exact match), optionally
expanding the results with links.
Relies on Entity.query() with a pre-built set of rules.
projects = projectal.Project.match('identifier', 'zmb-005')
103 @classmethod 104 def match_startswith(cls, field, term, links=None): 105 """Find entities where `field` starts with the text `term`, 106 optionally expanding the results with `links`. 107 108 Relies on `Entity.query()` with a pre-built set of rules. 109 ``` 110 projects = projectal.Project.match_startswith('name', 'Zomb') 111 ``` 112 """ 113 filter = [["STAFF.{}.{}".format(cls._name.upper(), field), "prefix", term]] 114 return cls.query(filter, links)
Find entities where field starts with the text term,
optionally expanding the results with links.
Relies on Entity.query() with a pre-built set of rules.
projects = projectal.Project.match_startswith('name', 'Zomb')
116 @classmethod 117 def match_endswith(cls, field, term, links=None): 118 """Find entities where `field` ends with the text `term`, 119 optionally expanding the results with `links`. 120 121 Relies on `Entity.query()` with a pre-built set of rules. 122 ``` 123 projects = projectal.Project.match_endswith('identifier', '-2023') 124 ``` 125 """ 126 term = "(?i).*{}$".format(term) 127 filter = [["STAFF.{}.{}".format(cls._name.upper(), field), "regex", term]] 128 return cls.query(filter, links)
Find entities where field ends with the text term,
optionally expanding the results with links.
Relies on Entity.query() with a pre-built set of rules.
projects = projectal.Project.match_endswith('identifier', '-2023')
130 @classmethod 131 def search(cls, fields=None, term="", case_sensitive=True, links=None): 132 """Find entities that contain the text `term` within `fields`. 133 `fields` is a list of field names to target in the search. 134 135 `case_sensitive`: Optionally turn off case sensitivity in the search. 136 137 Relies on `Entity.query()` with a pre-built set of rules. 138 ``` 139 projects = projectal.Project.search(['name', 'description'], 'zombie') 140 ``` 141 """ 142 filter = [] 143 term = "(?{}).*{}.*".format("" if case_sensitive else "?", term) 144 for field in fields: 145 filter.append( 146 ["STAFF.{}.{}".format(cls._name.upper(), field), "regex", term] 147 ) 148 filter = ["_or_", filter] 149 return cls.query(filter, links)
Find entities that contain the text term within fields.
fields is a list of field names to target in the search.
case_sensitive: Optionally turn off case sensitivity in the search.
Relies on Entity.query() with a pre-built set of rules.
projects = projectal.Project.search(['name', 'description'], 'zombie')
151 @classmethod 152 def query(cls, filter, links=None, timeout=30): 153 """Run a query on this entity with the supplied filter. 154 155 The query is already set up to target this entity type, and the 156 results will be converted into full objects when found, optionally 157 expanded with the `links` provided. You only need to supply a 158 filter to reduce the result set. 159 160 See [the filter documentation](https://projectal.com/docs/v1.1.1#section/Filter-section) 161 for a detailed overview of the kinds of filters you can construct. 162 """ 163 ids = [] 164 request_completed = False 165 limit = projectal.query_chunk_size 166 start = 0 167 while not request_completed: 168 payload = { 169 "name": "Python library entity query ({})".format(cls._name.upper()), 170 "type": "msql", 171 "start": start, 172 "limit": limit, 173 "select": [["STAFF.{}.uuId".format(cls._name.upper())]], 174 "filter": filter, 175 "timeout": timeout, 176 } 177 result = projectal.query(payload) 178 ids.extend(result) 179 if len(result) < limit: 180 request_completed = True 181 else: 182 start += limit 183 184 ids = [id[0] for id in ids] 185 if ids: 186 return cls.get(ids, links=links) 187 return []
Run a query on this entity with the supplied filter.
The query is already set up to target this entity type, and the
results will be converted into full objects when found, optionally
expanded with the links provided. You only need to supply a
filter to reduce the result set.
See the filter documentation for a detailed overview of the kinds of filters you can construct.