Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some fixes and production ready App. #2

Merged
merged 14 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"globals": {
"globalThis": true
},
"extends": ["next/core-web-vitals", "next", "prettier", "eslint:recommended"],
"ignorePatterns": ["src/types/**"],
"extends": ["next/core-web-vitals", "next", "prettier", "eslint:recommended"]
"rules": {
"@next/next/no-img-element": "off"
}
}
3 changes: 3 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[flake8]
extend-ignore = E203
max-line-length = 120
27 changes: 24 additions & 3 deletions .github/workflows/lint.yml → .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ name: CI

on:
push:
paths-ignore:
- README.md
- LICENSE

pull_request:
paths-ignore:
- README.md
- LICENSE
branches:
- main

Expand All @@ -19,16 +27,29 @@ jobs:
registry-url: https://registry.yarnpkg.com

- name: Cache Yarn dependencies
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: |
node_modules
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-

- name: Install dependencies
- name: Install Yarn dependencies
run: yarn install

- name: Lint
- name: Yarn Lint
run: yarn lint

- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.8
cache: 'pip'

- name: Install pip dependencies
run: python -m pip install --upgrade pip flake8

- name: Flake8
run: flake8 api core
22 changes: 9 additions & 13 deletions api/index.py → api/core/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@
from dotenv import load_dotenv
from flask import Flask, jsonify, request, send_file, session

# from flask_cors import CORS, cross_origin
from utils.wrappers import auth_required, destroy_build_session, session_keys

from api.builder.compress import FileResponse, win_compress, x11_compress
from api.builder.cursor import store_cursors
from api.utils.parser import parse_download_params, parse_upload_formdata
from api.utils.token import decode_auth_header
from core.builder.compress import FileResponse, win_compress, x11_compress
from core.builder.cursor import store_cursors
from core.utils.parser import parse_download_params, parse_upload_formdata
from core.utils.token import decode_auth_header
from core.utils.wrappers import auth_required, destroy_build_session, session_keys

load_dotenv()

Expand All @@ -19,11 +17,9 @@

app.secret_key = os.getenv("FLASK_SECRET")
app.config["SESSION_COOKIE_SAMESITE"] = "Lax"
# CORS(app, supports_credentials=True)


@app.route("/api/session", methods=["GET"])
# @cross_origin(origins="*")
@app.route("/api/core/session", methods=["GET"])
def get_session():
auth = decode_auth_header()

Expand All @@ -34,7 +30,7 @@ def get_session():
return jsonify({"id": auth.id, "role": auth.role})


@app.route("/api/session", methods=["DELETE"])
@app.route("/api/core/session", methods=["DELETE"])
def destroy_session():
k = session_keys["build"]
id = session.get(k, None)
Expand All @@ -45,7 +41,7 @@ def destroy_session():
return jsonify({"id": id})


@app.route("/api/upload", methods=["POST"])
@app.route("/api/core/upload", methods=["POST"])
@auth_required
def upload_images():
errors: List[str] = []
Expand All @@ -68,7 +64,7 @@ def upload_images():
return jsonify({"status": 200, "id": id, "file": name, "error": None})


@app.route("/api/download", methods=["GET"])
@app.route("/api/core/download", methods=["GET"])
def download():
errors: List[str] = []

Expand Down
6 changes: 3 additions & 3 deletions api/builder/compress.py → core/builder/compress.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
from clickgen.packer.windows import pack_win
from clickgen.packer.x11 import pack_x11

from api.builder.config import gsubtmp, gtmp
from api.builder.files import attach_files
from api.utils.parser import DownloadParams
from core.builder.config import gsubtmp, gtmp
from core.builder.files import attach_files
from core.utils.parser import DownloadParams


@dataclass
Expand Down
File renamed without changes.
26 changes: 5 additions & 21 deletions api/builder/cursor.py → core/builder/cursor.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,25 @@
import os
from logging import Logger
from typing import List, Union
from typing import List

from clickgen.parser import open_blob
from clickgen.writer import to_win, to_x11
from wand.api import library
from wand.color import Color
from wand.image import Image

from api.builder.config import configs, gsubtmp
from api.utils.parser import UploadFormData
from core.builder.config import configs, gsubtmp
from core.utils.parser import UploadFormData


def store_cursors(sid: str, data: UploadFormData, logger: Logger):
errors: List[str] = []

name = data.name
platform = data.platform
frames = data.frames
pngs = data.frames
size = data.size
delay = data.delay

pngs: List[bytes] = []

try:
for f in frames:
with Image() as image:
with Color("transparent") as background_color:
library.MagickSetBackgroundColor(
image.wand, background_color.resource
)
image.read(blob=f.encode(), format="svg")
png = image.make_blob("png32")
if type(png) is bytes:
pngs.append(png)

if not pngs:
if len(pngs) == 0:
errors.append("Unable to convert SVG to PNG")
return None, errors

Expand Down
2 changes: 1 addition & 1 deletion api/builder/files.py → core/builder/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from pathlib import Path
from typing import Literal

from api.utils.parser import DownloadParams
from core.utils.parser import DownloadParams

README = """[::] Bibata Cursor
TLDR; This cursor set is a masterpiece of cursors available on the internet,
Expand Down
8 changes: 5 additions & 3 deletions api/utils/parser.py → core/utils/parser.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import base64
from dataclasses import dataclass
from logging import Logger
from typing import List, Literal
Expand All @@ -8,7 +9,7 @@
@dataclass
class UploadFormData:
name: str
frames: List[str]
frames: List[bytes]
platform: str
size: int
delay: int
Expand All @@ -22,7 +23,7 @@ def parse_upload_formdata(request: Request, logger: Logger):
size: int = 0
delay: int = 0
platform: str = ""
frames: List[str] = []
frames: List[bytes] = []

try:
form_data = request.form.get("data")
Expand Down Expand Up @@ -77,7 +78,8 @@ def parse_upload_formdata(request: Request, logger: Logger):
f"Invalid 'frames[{i}]' type. It must be type 'string'"
)
else:
frames.append(v)
base64_str = v[len("data:image/png;base64,") :]
frames.append(base64.b64decode(base64_str))

except Exception as e:
errors.append(str(e))
Expand Down
2 changes: 1 addition & 1 deletion api/utils/token.py → core/utils/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def decode_auth_header():

auth_header = request.headers.get("Authorization")
if auth_header and auth_header.startswith("Bearer "):
token = auth_header[len("Bearer ") :] # noqa: E203
token = auth_header[len("Bearer ") :]
try:
auth = decode_token(token)
if auth == "expired":
Expand Down
4 changes: 2 additions & 2 deletions api/utils/wrappers.py → core/utils/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

from flask import g, jsonify, session

from api.builder.config import gtmp
from api.utils.token import decode_auth_header
from core.builder.config import gtmp
from core.utils.token import decode_auth_header

session_keys = {"build": "cbuid"}

Expand Down
21 changes: 6 additions & 15 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
const devMode = process.env.NODE_ENV === 'development';

/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'avatars.githubusercontent.com',
port: '',
pathname: '/u/**'
}
]
},
rewrites: async () => {
return [
{
source: '/api/core/:path*',
destination:
process.env.NODE_ENV === 'development'
? 'http://localhost:5328/api/:path*'
: '/api/'
source: devMode ? '/api/core/:path*' : '/api/:path*',
destination: devMode
? 'http://localhost:5328/api/core/:path*'
: '/api/:path*'
}
];
}
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "1.0.0-alpha.0",
"private": true,
"scripts": {
"flask-dev": "pip3 install --upgrade pip && pip3 install -r requirements.txt && python3 -m flask --debug --app api/index run -p 5328 ",
"flask-dev": "pip3 install --upgrade pip && pip3 install -r requirements.txt && python3 -m flask --debug --app api/core/index run -p 5328 ",
"next-dev": "next dev",
"dev": "concurrently \"yarn next-dev\" \"yarn flask-dev\"",
"prebuild": "node -p \"'export const LIB_VERSION = ' + JSON.stringify(require('./package.json').version) + ';'\" > src/version.ts",
Expand All @@ -24,6 +24,7 @@
"next-auth": "^4.24.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"sharp": "^0.32.6",
"swr": "^2.2.4",
"uuid": "^9.0.1"
},
Expand Down
5 changes: 1 addition & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
Flask==2.2.2
Werkzeug==2.2.2
Flask-Cors===4.0.0
Flask==3.0.0
python-dotenv===1.0.0
PyJWT===2.8.0
Wand===0.6.11
clickgen===2.1.9
4 changes: 2 additions & 2 deletions src/app/(home)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ export const metadata: Metadata = {
manifest: '/favicon/site.webmanifest'
};

interface Props {
type Props = {
children: React.ReactNode;
}
};

export default function RootLayout({ children }: Props) {
return (
Expand Down
30 changes: 19 additions & 11 deletions src/app/(home)/studio/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { useEffect, useState } from 'react';
import { useSession } from 'next-auth/react';

import { TYPES, PREBUILT_COLORS, SIZES } from '@root/configs';
import { useSecureStorage as useStorage } from '@hooks/useSecureStorage';

import { TypePicker } from '@components/TypePicker';
import { SizePicker } from '@components/SizePicker';
Expand All @@ -17,11 +16,11 @@ import { genAccessToken } from '@utils/auth/token';
import { Image } from 'bibata/core-api/types';

export default function StudioPage() {
const [type, setType] = useStorage<string>('type', TYPES[0]);
const [cursorSize, setCursorSize] = useStorage('cursorSize', SIZES[0]);
const [type, setType] = useState(TYPES[0]);
const [cursorSize, setCursorSize] = useState(SIZES[0]);

const [colorName, setColorName] = useStorage('colorName', 'Amber');
const [color, setColor] = useStorage('color', PREBUILT_COLORS[colorName]);
const [colorName, setColorName] = useState('Amber');
const [color, setColor] = useState(PREBUILT_COLORS[colorName]);

// eslint-disable-next-line no-unused-vars
const [animationDelay, setAnimationDelay] = useState<number>(15);
Expand All @@ -37,13 +36,17 @@ export default function StudioPage() {
setImagesCount(0);
};

const refreshToken = () => {
if (session?.user) {
setToken(genAccessToken(session.user));
} else {
setToken(genAccessToken());
}
};

useEffect(() => {
if (status !== 'loading') {
if (session?.accessToken) {
setToken(session.accessToken);
} else {
setToken(genAccessToken());
}
refreshToken();
}
}, [status, update]); // eslint-disable-line react-hooks/exhaustive-deps

Expand All @@ -55,14 +58,18 @@ export default function StudioPage() {
onClick={(v) => {
resetImages();
setType(v);
refreshToken();
}}
/>

<div className='mt-10'>
<SizePicker
list={SIZES}
values={cursorSize}
onClick={(s) => setCursorSize(s)}
onClick={(s) => {
setCursorSize(s);
refreshToken();
}}
/>
</div>

Expand All @@ -74,6 +81,7 @@ export default function StudioPage() {
resetImages();
setColorName(n);
setColor(c);
refreshToken();
}}
/>
</div>
Expand Down
Loading