def to_api_dict(self, authorizer: Authorizer = None): data = { 'completed': self.completed, 'created': int(time.time()), 'objective': self.objective_key, 'stage': split_key(self.objective_key)[0], 'area': split_key(self.objective_key)[1], 'score': self.score, 'line': int(split_key(self.objective_key)[2].split('.')[0]), 'subline': int(split_key(self.objective_key)[2].split('.')[1]), 'original-objective': self.original_objective, 'personal-objective': self.personal_objective, 'tasks': [{ 'completed': task.completed, 'description': task.description, } for task in self.tasks], } if authorizer is not None: data['token'] = self.generate_token(authorizer, duration=timedelta(days=1)) return data
def complete_active_task(event: HTTPEvent) -> JSONResponse: sub = event.params['sub'] if event.authorizer.sub != sub and not event.authorizer.is_scouter: return JSONResponse.generate_error( HTTPError.FORBIDDEN, "You have no access to this resource with this user") completed_task = TasksService.complete_active_task(event.authorizer) if completed_task is None: return JSONResponse.generate_error(HTTPError.NOT_FOUND, "No active task found") area = split_key(completed_task['objective'])[1] response = JSONResponse({ 'message': 'Completed task', 'task': completed_task, 'reward': RewardsFactory.get_reward_token_by_reason( authorizer=event.authorizer, area=area, reason=RewardReason.COMPLETE_OBJECTIVE), }) LogsService.create( event.authorizer.sub, LogTag.COMPLETED.join(completed_task['objective'].upper()), 'Completed an objective!', {}) return response
def update_avatar(cls, user_sub: str, avatar: dict): interface = cls.get_interface() parts_ids = [part_id for part_id in set(avatar.values()) if part_id is not None] if len(parts_ids) > 0: logs = LogsService.batch_get( [LogKey(sub=user_sub, tag=join_key('REWARD', 'AVATAR', part_id)) for part_id in parts_ids], attributes=['data', 'tag']) if len(logs) != len(parts_ids): raise NotFoundException("An avatar part was not found") else: logs = [] avatar_parts = {int(split_key(log.tag)[-1]): Reward.from_api_map(log.data).to_api_map() for log in logs} new_avatar = { 'left_eye': avatar_parts.get(avatar.get('left_eye')), 'right_eye': avatar_parts.get(avatar.get('right_eye')), "mouth": avatar_parts.get(avatar.get('mouth')), "top": avatar_parts.get(avatar.get('top')), "bottom": avatar_parts.get(avatar.get('bottom')), "neckerchief": avatar_parts.get(avatar.get('neckerchief')) } interface.update(user_sub, updates={'avatar': new_avatar}) return new_avatar
def create_log(event: HTTPEvent): user_sub: str = event.params['sub'] tag: str = event.params['tag'].upper() if event.authorizer.sub != user_sub: raise ForbiddenException("Only the same user can create logs") parent_tag = LogTag.from_short(split_key(tag)[0]) if parent_tag not in USER_VALID_TAGS: raise ForbiddenException(f"A user can only create logs with the following tags: {USER_VALID_TAGS}") body = event.json log = body['log'] data = body.get('data') if len(body) > 1024: raise InvalidException(f"A log can't have more than 1024 characters") if data is not None: if len(json.dumps(data)) > 2048: raise InvalidException(f"Log data is too big") response_body = {} if parent_tag == LogTag.PROGRESS: if tag != parent_tag.short: raise InvalidException(f"A progress log tag can't be compound") if body.get('token') is None: raise InvalidException(f"To post a PROGRESS log you must provide the task token") objective = TasksService.get_task_token_objective(body['token'], authorizer=event.authorizer) tag = join_key(LogTag.PROGRESS.value, objective).upper() now = int(datetime.now(timezone.utc).timestamp() * 1000) last_progress_log = LogsService.get_last_log_with_tag(event.authorizer.sub, tag.upper()) if last_progress_log is None or now - last_progress_log.timestamp > 24 * 60 * 60 * 1000: response_body['token'] = RewardsFactory.get_reward_token_by_reason(authorizer=event.authorizer, area=split_key(objective)[1], reason=RewardReason.PROGRESS_LOG) log = LogsService.create(user_sub, tag, log_text=log, data=body.get('data'), append_timestamp_to_tag=True) response_body['item'] = log.to_api_map() return JSONResponse(body=response_body)
def query_logs(event: HTTPEvent): user_sub = event.params['sub'] tag = LogTag.normalize(split_key(event.params['tag'])).upper() if event.params.get('tag') else None limit = event.queryParams.get('limit', 25) if not isinstance(limit, int) or limit > 100: raise InvalidException("Limit must be an integer and lower or equal than 100") logs = LogsService.query(user_sub, tag, limit=limit) return JSONResponse(body=QueryResult.from_list([log.to_api_map() for log in logs]).as_dict())
def to_api_map(self): tag: str = self.tag.name if isinstance(self.tag, LogTag) else self.tag long_tag: str = tag if not self.append_timestamp else join_key( tag, self.timestamp) data = { "tag": self.parent_tag.normalize(split_key(long_tag), short=True), "user": self.sub, "log": self.log, 'timestamp': self.timestamp } if self.data is not None: data['data'] = self.data return data
def normalize(tag: List[str], short=False): parent_tag_full = LogTag.from_tag(tag, short=False) parent_tag = LogTag.from_tag( tag, short=True) if parent_tag_full is None else parent_tag_full if parent_tag is None: raise InvalidException(f'Tag {join_key(*tag)} does not exist') source_is_short = parent_tag_full is None tag_body = tag[ 1 if source_is_short else len(split_key(parent_tag.value)):] if not short: return join_key(parent_tag.value, *tag_body) else: return join_key(parent_tag.short, *tag_body)
def from_db_map(beneficiary: dict): if beneficiary is None: return None from core.services.tasks import Task user_sub = beneficiary.get("user") district_group = beneficiary.get("group") district, group = district_group.split("::") if district_group is not None else (None, None) unit_user = beneficiary.get("unit-user") unit = split_key(unit_user)[0] if unit_user is not None else None full_name = beneficiary.get("full-name") nickname = beneficiary.get("nickname") raw_birthdate = beneficiary.get("birthdate") birthdate = datetime.strptime(raw_birthdate, "%d-%m-%Y") if raw_birthdate is not None else None score = beneficiary.get("score") score = {area: int(score.get(area, 0)) for area in VALID_AREAS} if score is not None else None n_tasks = beneficiary.get("n_tasks") n_tasks = {area: int(n_tasks.get(area, 0)) for area in VALID_AREAS} if n_tasks is not None else None target = beneficiary.get("target") target = Task.from_db_dict(target) if target is not None else None bought_items = beneficiary.get("bought_items", {}) set_base_tasks = beneficiary.get("set_base_tasks", False) generated_token_last = int(beneficiary.get("generated_token_last", -1)) n_claimed_tokens = int(beneficiary.get("n_claimed_tokens", -1)) profile_picture = beneficiary.get('profile_picture') return Beneficiary(user_sub=user_sub, full_name=full_name, nickname=nickname, district=district, group=group, unit=unit, score=score, n_tasks=n_tasks, birthdate=birthdate, target=target, bought_items=bought_items, set_base_tasks=set_base_tasks, n_claimed_tokens=n_claimed_tokens, generated_token_last=generated_token_last, profile_picture=profile_picture)
def clear_active_task(cls, authorizer: Authorizer, return_values: UpdateReturnValues = UpdateReturnValues.UPDATED_OLD, receive_score=False ): interface = cls.get_interface() updates = {'target': None} add_to = None if receive_score: beneficiary = BeneficiariesService.get(authorizer.sub, ["target"]) if beneficiary.target is None: return None score = ScoreConfiguration.instance().base_score area = split_key(beneficiary.target.objective_key)[1] add_to = { f'score.{area}': score, f'n_tasks.{area}': 1 } try: return interface.update(authorizer.sub, updates, None, return_values=return_values, add_to=add_to, conditions=Attr('target').ne(None))["Attributes"] except interface.client.exceptions.ConditionalCheckFailedException: raise InvalidException('No active target')
def short(self): return split_key(self.value)[-1]
def tags(self) -> List[str]: return split_key(self.tag)
def process_beneficiary_code(code: str): num, district, group = split_key(code) return {"district": district, "code": num, "group": group}