コード例 #1
0
    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)
コード例 #2
0
 def from_tag(tag: List[str], short=False):
     tag = join_key(*tag)
     for member in LogTag:
         value = member.short if short else member.value
         if len(tag) >= len(value) and value == tag[:len(value)]:
             return member
     return None
コード例 #3
0
    def start_task(cls, authorizer: Authorizer, stage: str, area: str,
                   subline: str, tasks: List[str], description: str):
        from core.services.beneficiaries import BeneficiariesService
        line_, subline_ = subline.split('.')
        objective = ObjectivesService.get(stage, area, int(line_),
                                          int(subline_))

        now = datetime.now(timezone.utc)
        task = Task(created=int(now.timestamp() * 1000),
                    completed=False,
                    objective_key=join_key(stage, area, subline),
                    original_objective=objective,
                    personal_objective=description,
                    tasks=[
                        Subtask(completed=False, description=description)
                        for description in tasks
                    ])

        try:
            BeneficiariesService.update(authorizer,
                                        active_task=task.to_db_dict())
        except BeneficiariesService.exceptions(
        ).ConditionalCheckFailedException:
            return None
        return task
コード例 #4
0
 def get(cls, sub: str, stage: str, area: str, line: int,
         subline: int) -> Task:
     interface = cls.get_interface()
     item = interface.get(sub, join_key(stage, area,
                                        f"{line}.{subline}")).item
     if item is None:
         raise NotFoundException('Task not found')
     return Task.from_db_dict(item)
コード例 #5
0
 def add_to_scout_group(cls, username: str, district: str, group: str,
                        current_groups: List[str]):
     client = cls.get_client()
     new_group = join_key(district, group)
     if new_group in current_groups:
         return
     client.admin_update_user_attributes(
         UserPoolId=cls.__user_pool_id__,
         Username=username,
         UserAttributes=[
             {
                 'Name': 'custom:groups',
                 'Value':
                 ','.join(current_groups + [join_key(district, group)])
             },
         ],
     )
コード例 #6
0
 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
コード例 #7
0
 def query(cls, sub: str, stage: str = None, area: str = None):
     interface = cls.get_interface()
     args = [arg for arg in (stage, area) if arg is not None]
     sort_key = (Operator.BEGINS_WITH,
                 join_key(*args, '')) if len(args) > 0 else None
     return QueryResult.from_list([
         Task.from_db_dict(item) for item in interface.query(
             partition_key=sub,
             sort_key=sort_key,
             attributes=[
                 'objective', 'original-objective', 'personal-objective',
                 'completed', 'tasks', 'user'
             ]).items
     ])
コード例 #8
0
def get_user_active_task(event: HTTPEvent) -> JSONResponse:
    sub = event.params['sub']
    result = TasksService.get_active_task(sub)
    beneficiary_authorizer = event.authorizer if event.authorizer is not None and event.authorizer.sub == sub else None
    d = result.to_api_dict(authorizer=beneficiary_authorizer)
    if beneficiary_authorizer is not None:
        # generate log reward claim token
        last_task_log = LogsService.get_last_log_with_tag(
            sub,
            tag=join_key(LogTag.PROGRESS.value, result.objective_key).upper())
        d['eligible_for_progress_reward'] = last_task_log is None or int(
            time.time() * 1000) - last_task_log.timestamp > 24 * 60 * 60 * 1000

    return JSONResponse(d)
コード例 #9
0
 def create(cls,
            sub: str,
            tag: str,
            log_text: str,
            data: Any,
            append_timestamp_to_tag: bool = False) -> Log:
     log = Log(tag=tag.upper(),
               log=log_text,
               data=data,
               timestamp=cls._get_current_timestamp(),
               sub=sub,
               append_timestamp=append_timestamp_to_tag)
     cls.get_interface().create(
         sub, log.to_db_map(),
         join_key(log.tag, log.timestamp)
         if log.append_timestamp else log.tag)
     return log
コード例 #10
0
    def to_db_map(self):
        tag = self.tag.name if isinstance(self.tag, LogTag) else self.tag
        data = {
            "tag":
            tag if not self.append_timestamp else join_key(
                tag, self.timestamp),
            'user':
            self.sub,
            'log':
            self.log,
            'timestamp':
            self.timestamp
        }

        if self.data is not None:
            data['data'] = self.data
        return data
コード例 #11
0
 def _add_objectives_as_completed(cls, authorizer: Authorizer,
                                  objectives: List[ObjectiveKey]):
     # noinspection PyProtectedMember
     model = cls.get_interface()._model
     client = model.get_table().meta.client
     now = datetime.now(timezone.utc)
     now = int(now.timestamp() * 1000)
     n_chunks = math.ceil(len(objectives) / 25)
     # do batch writes in chunks of 25 to avoid errors
     for i_chunk in range(n_chunks):
         start = i_chunk * 25
         end = min((i_chunk + 1) * 25, len(objectives))
         chunk = objectives[start:end]
         request_items = {
             model.__table_name__: [{
                 'PutRequest': {
                     'Item': {
                         'completed':
                         True,
                         'created':
                         now,
                         'objective':
                         join_key(authorizer.stage, key.area,
                                  f'{key.line}.{key.subline}'),
                         'original-objective':
                         ObjectivesService.get(authorizer.stage, key.area,
                                               key.line, key.subline),
                         'personal-objective':
                         None,
                         'score':
                         0,
                         'tasks': [],
                         'user':
                         authorizer.sub
                     },
                 }
             } for key in chunk]
         }
         client.batch_write_item(RequestItems=request_items)
コード例 #12
0
 def generate_beneficiary_code(district: str, group_code: str):
     h = hashlib.sha1(join_key(district, group_code).encode()).hexdigest()
     int_hash = (int(h, 16) + random.randint(0, 1024)) % (10**8)
     return f'{int_hash:08}'
コード例 #13
0
 def join(self, body: str):
     return join_key(self.value, body)
コード例 #14
0
 def concat(parent_tag: str, *args):
     return join_key(parent_tag, *args)
コード例 #15
0
class LogTag(Enum):
    REWARD = 'REWARD'
    PROGRESS = join_key('STATS', 'PROGRESS')
    COMPLETED = join_key('STATS', 'COMPLETED')

    @staticmethod
    def concat(parent_tag: str, *args):
        return join_key(parent_tag, *args)

    def join(self, body: str):
        return join_key(self.value, body)

    @property
    def short(self):
        return split_key(self.value)[-1]

    @staticmethod
    def from_value(value: str):
        for member in LogTag:
            if value == member.value:
                return member
        return None

    @staticmethod
    def from_short(value: str):
        for member in LogTag:
            if value == member.short:
                return member
        return None

    @staticmethod
    def from_tag(tag: List[str], short=False):
        tag = join_key(*tag)
        for member in LogTag:
            value = member.short if short else member.value
            if len(tag) >= len(value) and value == tag[:len(value)]:
                return member
        return None

    @staticmethod
    def get_parent_tag(tag: List[str]) -> Optional[Enum]:
        parent_tag_full = LogTag.from_tag(tag, short=False)
        return LogTag.from_tag(
            tag, short=True) if parent_tag_full is None else parent_tag_full

    @staticmethod
    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)

    @staticmethod
    def shorten(tag: List[str]):
        return LogTag.normalize(tag, short=True)
コード例 #16
0
 def generate_scouters_code(district: str, group_code: str):
     return hashlib.sha1(join_key(district,
                                  group_code).encode()).hexdigest()
コード例 #17
0
 def get_user_rewards(cls, authorizer: Authorizer, category: RewardType):
     tag = join_key(LogTag.REWARD.name, category.name)
     return LogsService.query(authorizer.sub, tag, limit=None)
コード例 #18
0
    def claim_reward(cls, authorizer: Authorizer, reward_token: str, release: int, box_index: int = None) -> \
            List[Reward]:
        from core.services.beneficiaries import BeneficiariesService

        jwk_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                                'jwk.json')
        with open(jwk_path, 'r') as f:
            jwk = jwt.jwk_from_dict(json.load(f))

        decoder = jwt.JWT()
        try:
            decoded = decoder.decode(reward_token, jwk)
        except JWTDecodeError as e:
            raise InvalidException(f'Invalid token: {e.args}')

        now = get_int_from_datetime(datetime.now())
        if now > decoded["exp"]:
            raise ForbiddenException("The reward token has expired")
        if authorizer.sub != decoded["sub"]:
            raise ForbiddenException(
                "This token does not belong to the claimer")
        BeneficiariesService.set_reward_index(authorizer, decoded['index'])

        boxes = decoded["boxes"]
        probabilities: List[RewardProbability] = [
            RewardProbability.from_map(reward) for reward in decoded["static"]
        ]
        if len(boxes) > 0:
            if box_index is None:
                raise InvalidException("A box must be chosen")
            if box_index >= len(boxes):
                raise InvalidException(
                    f"Box index out of range, it must be between 0 (inclusive) and {len(boxes)} (exclusive)"
                )
            probabilities += [
                RewardProbability.from_map(reward)
                for reward in boxes[box_index]
            ]
        rewards = [
            RewardsService.get_random(probability.type, release,
                                      probability.rarity)
            for probability in probabilities
        ]
        LogsService.batch_create(logs=[
            Log(sub=authorizer.sub,
                tag=join_key(LogTag.REWARD.name, rewards[reward_i].type.name,
                             rewards[reward_i].id),
                log='Won a reward',
                data=rewards[reward_i].to_api_map(),
                append_timestamp=rewards[reward_i].type != RewardType.AVATAR)
            for reward_i in range(len(rewards))
        ])

        area: Optional[str] = decoded.get('area')
        areas: List[str] = VALID_AREAS if area is None else [area]

        scores = {}
        for r in rewards:
            if r.type != RewardType.POINTS:
                continue
            total_score = r.description['amount']
            for a in areas:
                scores[a] = scores.get(a, 0) + (total_score / len(areas))

        for key in scores:
            scores[key] = math.ceil(scores[key])

        BeneficiariesService.add_score(authorizer.sub, scores)
        return rewards