コード例 #1
0
ファイル: auth.py プロジェクト: obasys/hikka
    def post(self):
        result = {"error": None, "data": {}}

        parser = reqparse.RequestParser()
        parser.add_argument("password", type=str, required=True)
        parser.add_argument("email", type=str, required=True)
        args = parser.parse_args()

        account = UserService.get_by_email(args["email"])
        if account is None:
            return abort("account", "not-found")

        login = UserService.login(args["password"], account.password)
        if not login:
            return abort("account", "login-failed")

        UserService.update(account, login=datetime.now)
        token = Token.create("login", account.username)
        data = Token.validate(token)

        result["data"] = {
            "token": token,
            "expire": data["payload"]["expire"],
            "username": data["payload"]["meta"]
        }

        return result
コード例 #2
0
def update_comment():
    result = {"error": None, "data": {}}

    parser = RequestParser()
    parser.argument("counter", type=int, required=True)
    parser.argument("params", type=dict, default={})
    args = parser.parse()

    params_parser = RequestParser()
    params_parser.argument("text", type=helpers.string, required=True, location=("params"))
    params_args = params_parser.parse(req=args)

    comment = CommentService.get_by_counter(args["counter"], request.account)
    if comment is None:
        return abort("comment", "not-found")

    if datetime.utcnow() - comment.created > timedelta(minutes=20):
        return abort("comment", "not-editable")

    comment.text = params_args["text"]
    comment.updated = datetime.utcnow()
    comment.save()

    result["data"] = comment.dict()
    return result
コード例 #3
0
ファイル: descriptors.py プロジェクト: obasys/hikka
    def post(self):
        result = {"error": None, "data": {}}

        parser = reqparse.RequestParser()
        parser.add_argument("service",
                            type=str,
                            required=True,
                            choices=choices)
        parser.add_argument("slug", type=str, required=True)
        parser.add_argument("params", type=dict, default={})
        args = parser.parse_args()

        descriptor = DescriptorService.get_by_slug(args["service"],
                                                   args["slug"])
        if descriptor is None:
            return abort(args["service"], "not-found")

        keys = ["name", "slug", "description"]
        update = utils.filter_dict(args["params"], keys)
        update_document(descriptor, update)

        try:
            descriptor.save()
        except Exception:
            return abort("general", "empty-required")

        result["data"] = descriptor.dict()
        return result
コード例 #4
0
    def post(self):
        result = {"error": None, "data": {}}

        parser = reqparse.RequestParser()
        parser.add_argument("position", type=int, required=True)
        parser.add_argument("team", type=str, required=True)
        parser.add_argument("slug", type=str, required=True)
        args = parser.parse_args()

        team = TeamService.get_by_slug(args["team"])
        if team is None:
            return abort("team", "not-found")

        if request.account not in team.members:
            return abort("account", "not-team-member")

        anime = AnimeService.get_by_slug(args["slug"])
        if anime is None:
            return abort("anime", "not-found")

        episode = AnimeService.find_position(anime, args["position"])
        if episode is None:
            return abort("episodes", "not-found")

        FileService.destroy(episode.video)
        AnimeService.remove_episode(anime, episode)

        result["data"] = anime.dict(True)
        return result
コード例 #5
0
    def load(self, size, index, total, offset):
        if size != self.chunk_size:
            self.clean(self.publisher)
            return abort("file", "invalid-size")

        if index >= total or index < 0:
            self.clean(self.publisher)
            return abort("file", "invalid-index")

        if not self.publisher:
            if self.chunk_size > max_size:
                return abort("file", "too-big")

            if os.path.isfile(self.blob_file):
                if os.path.getsize(self.blob_file) > max_size:
                    return abort("file", "too-big")

        if not os.path.isdir(self.tmp_dir):
            os.makedirs(self.tmp_dir)

        tmp_ls = os.listdir(self.tmp_dir)

        if self.uuid not in tmp_ls:
            if not self.publisher:
                self.clean()
                os.makedirs(self.tmp_dir)

            os.mkdir(self.uuid_dir)

        with open(self.blob_file, "ab") as blob:
            blob.seek(offset)
            blob.write(self.file.stream.read())
コード例 #6
0
def join(args):
    result = {"error": None, "data": {}}

    if UserService.get_by_username(args["username"]):
        return abort("account", "username-exist")

    if UserService.get_by_email(args["email"]):
        return abort("account", "email-exist")

    account = UserService.create(
        args["username"],
        auth.hashpwd(args["password"]),
        args["email"]
    )

    email = mail.Email()
    activation_token = Token.create("activation", account.username)
    email.account_confirmation(account, activation_token)

    result["data"] = {
        "login": int(datetime.timestamp(account.login)),
        "username": account.username
    }

    # Display activation code only in debug mode
    if config.debug:
        result["data"]["code"] = activation_token

    # ToDo: Add permissions here

    return result
コード例 #7
0
ファイル: auth.py プロジェクト: obasys/hikka
    def post(self):
        result = {"error": None, "data": {}}

        parser = reqparse.RequestParser()
        parser.add_argument("token", type=str, required=True)
        args = parser.parse_args()

        data = Token.validate(args["token"])
        if not data["valid"]:
            return abort("general", "token-invalid-type")

        account = UserService.get_by_username(data["payload"]["meta"])
        if account is None:
            return abort("account", "not-found")

        if data["payload"]["action"] != "activation":
            return abort("general", "token-invalid-type")

        activated = PermissionService.check(account, "global", "activated")
        if activated:
            return abort("account", "activated")

        PermissionService.add(account, "global", "activated")
        result["data"] = {"username": account.username, "activated": True}

        return result
コード例 #8
0
def activate(args):
    result = {"error": None, "data": {}}

    if not Token.validate(args["token"]):
        return abort("general", "token-invalid")

    payload = Token.payload(args["token"])

    if not (account := UserService.get_by_username(payload["meta"])):
        return abort("account", "not-found")
コード例 #9
0
def password(data):
    if type(data) is not str:
        response = abort("general", "not-found")
        flask_abort(response)

    if len(data) < 8 or len(data) > 32:
        response = abort("general", "password-length")
        flask_abort(response)

    return data
コード例 #10
0
ファイル: upload.py プロジェクト: obasys/hikka
    def upload_image(self):
        if not self.is_image():
            return abort("file", "bad-mime-type")

        if self.size() > image_max_size:
            return abort("file", "too-big")

        storage_file_name = self.file.name + "." + "jpg"
        os.makedirs(self.tmp_dir)

        self.upload.save(self.tmp_dir + self.file.name + "." + self.file_type)
        pil = Image.open(self.tmp_dir + self.file.name + "." + self.file_type)
        width, height = pil.size

        if self.upload_type == "avatar":
            avatar_size = 250

            if width != height:
                self.clean()
                return abort("image", "not-square")

            if width < avatar_size:
                self.clean()
                return abort("image", "small-image")

            pil = pil.resize((avatar_size, avatar_size), Image.LANCZOS)

        if self.upload_type == "poster":
            max_width = 500
            if width > max_width:
                new_width = max_width
                new_height = int(new_width * height / width)
                pil = pil.resize((new_width, new_height), Image.LANCZOS)

        tmp_path = self.tmp_dir + storage_file_name
        pil.save(tmp_path, optimize=True, quality=95)

        storage_path = self.storage_dir + storage_file_name
        self.fs.put(tmp_path, storage_path)
        self.fs.chmod(storage_path, 'public-read')

        self.clean()

        self.file.path = f"/{self.branch}/{self.upload_type}/{self.folder}/{storage_file_name}"
        self.file.uploaded = True
        self.file.save()

        return self.file
コード例 #11
0
def genre(slug):
    genre = static.key("genres", slug)
    if not genre:
        response = abort("genre", "not-found")
        flask_abort(response)

    return genre
コード例 #12
0
    def parse(self, req=None, strict=False, http_error_code=400):
        if req is None:
            req = request

        namespace = self.namespace_class()

        req.unparsed_arguments = dict(
            self.argument_class("").source(req)) if strict else {}
        errors = {}
        for arg in self.args:
            value, found = arg.parse(req, self.bundle_errors)
            if isinstance(value, ValueError):
                errors.update(found)
                found = None
            if found or arg.store_missing:
                namespace[arg.dest or arg.name] = value

            if type(value) is Response:
                flask_abort(value)

        if errors:
            response = abort("general", "missing-field")
            flask_abort(response)

        if strict and req.unparsed_arguments:
            raise exceptions.BadRequest(
                "Unknown arguments: %s" %
                ", ".join(req.unparsed_arguments.keys()))

        return namespace
コード例 #13
0
def status(slug):
    status = static.key("statuses", slug)
    if not status:
        response = abort("status", "not-found")
        flask_abort(response)

    return status
コード例 #14
0
def uuid(data):
    expression = r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
    if not bool(re.search(expression, data)):
        response = abort("general", "bad-regex")
        flask_abort(response)

    return data
コード例 #15
0
def email(data):
    expression = r"[^@]+@[^@]+\.[^@]+"
    if not bool(re.search(expression, data)):
        response = abort("general", "bad-regex")
        flask_abort(response)

    return data
コード例 #16
0
def descriptor_service(slug):
    descriptor = static.key("descriptors", slug)
    if not descriptor:
        response = abort("descriptors", "not-found")
        flask_abort(response)

    return descriptor
コード例 #17
0
def team(slug):
    team = TeamService.get_by_slug(slug)
    if not team:
        response = abort("team", "not-found")
        flask_abort(response)

    return team
コード例 #18
0
def account(username):
    account = UserService.get_by_username(username)
    if not account:
        response = abort("account", "not-found")
        flask_abort(response)

    return account
コード例 #19
0
def new_team():
    result = {"error": None, "data": {}}

    parser = RequestParser()
    parser.argument("members", type=list, default=[], location="json")
    parser.argument("admins", type=list, default=[], location="json")
    parser.argument("description", type=str, required=True)
    parser.argument("name", type=str, required=True)
    parser.argument("slug", type=str, required=True)
    args = parser.parse()

    team = TeamService.get_by_slug(args["slug"])
    if team:
        return abort("team", "slug-exists")

    team = TeamService.create(args["name"], args["slug"], args["description"])

    for username in args["members"]:
        account = helpers.account(username)
        TeamService.add_member(team, account)
        if account.username in args["admins"]:
            PermissionService.add(account, "global", "publishing")

    result["data"] = team.dict(True)
    return result
コード例 #20
0
def category(slug):
    category = static.key("categories", slug)
    if not category:
        response = abort("category", "not-found")
        flask_abort(response)

    return category
コード例 #21
0
def franchise(slug):
    franchise = DescriptorService.get_by_slug("franchise", slug)
    if not franchise:
        response = abort("franchise", "not-found")
        flask_abort(response)

    return franchise
コード例 #22
0
def content(slug):
    content = static.key("content", slug)
    if not content:
        response = abort("content", "not-found")
        flask_abort(response)

    return content
コード例 #23
0
ファイル: decorators.py プロジェクト: obasys/hikka
    def decorator(*args, **kwargs):
        account = UserService.auth(request.headers.get("Authentication"))
        if account is None:
            return abort("account", "login-failed")

        request.account = account
        return view_function(*args, **kwargs)
コード例 #24
0
ファイル: anime.py プロジェクト: obasys/hikka
    def put(self):
        result = {"error": None, "data": []}
        choices = ("poster", "banner")

        parser = reqparse.RequestParser()
        parser.add_argument("file", type=FileStorage, location="files")
        parser.add_argument("type", type=str, choices=choices)
        parser.add_argument("slug", type=str, required=True)
        args = parser.parse_args()

        anime = AnimeService.get_by_slug(args["slug"])
        if anime is None:
            return abort("anime", "not-found")

        if args["file"] is not None:
            helper = UploadHelper(request.account, args["file"], args["type"])
            data = helper.upload_image()

            if type(data) is Response:
                return data

            if anime[args["type"]] is not None:
                FileService.destroy(anime[args["type"]])

            anime[args["type"]] = data
            anime.save()

        result["data"] = anime.dict()
        return result
コード例 #25
0
def state(slug):
    state = static.key("states", slug)
    if not state:
        response = abort("state", "not-found")
        flask_abort(response)

    return state
コード例 #26
0
    def post(self):
        result = {"error": None, "data": {}}

        parser = reqparse.RequestParser()
        parser.add_argument("descriptors",
                            type=list,
                            default=[],
                            location="json")
        args = parser.parse_args()

        result["data"]["search"] = {}
        data = {}

        for service in args["descriptors"]:
            if service not in choices:
                return abort("general", "service-not-found")

            data[service] = []
            descriptors = DescriptorService.list(service)
            for descriptor in descriptors:
                data[service].append(descriptor.dict())

        result["data"]["search"]["descriptors"] = data
        result["data"]["search"]["years"] = AnimeService.years()

        return result
コード例 #27
0
    def post(self):
        result = {"error": None, "data": {}}

        parser = reqparse.RequestParser()
        parser.add_argument("action",
                            type=str,
                            required=True,
                            choices=("add", "remove"))
        parser.add_argument("username", type=str, required=True)
        parser.add_argument("scope", type=str, required=True)
        parser.add_argument("name", type=str, required=True)
        args = parser.parse_args()

        account = UserService.get_by_username(args["username"])
        if account is None:
            return abort("account", "not-found")

        if args["action"] == "add":
            PermissionService.add(account, args["scope"], args["name"])

        elif args["action"] == "remove":
            PermissionService.remove(account, args["scope"], args["name"])

        result["data"] = account.list_permissions()
        return result
コード例 #28
0
    def upload_video(self):
        if not self.is_video():
            response = abort("file", "bad-mime-type")
            flask_abort(response)

        if not self.is_h264():
            response = abort("file", "bad-codec")
            flask_abort(response)

        storage_file_name = self.file.name + ".mp4"

        storage_path = self.storage_dir + storage_file_name
        tmp_path = self.path

        self.finish(tmp_path, storage_path, storage_file_name)

        return self.file
コード例 #29
0
def image_link(data):
    # Based on
    # https://stackoverflow.com/a/51493215/9217774
    expression = r"^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+(?:png|jpg|jpeg)+$"
    if not bool(re.search(expression, data)):
        response = abort("general", "not-file-link")
        flask_abort(response)

    return data
コード例 #30
0
    def get(self, slug):
        result = {"error": None, "data": {}}

        team = TeamService.get_by_slug(slug)
        if team is None:
            return abort("team", "not-found")

        result["data"] = team.dict(True)
        return result