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

Add apps api #48

Merged
merged 20 commits into from
Nov 21, 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
24 changes: 23 additions & 1 deletion hiddifypanel/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,31 @@


def create_app(cli=False, **config):

app = APIFlask(__name__, static_url_path="/<proxy_path>/static/", instance_relative_config=True, version='2.0.0', title="Hiddify API",
openapi_blueprint_url_prefix="/<proxy_path>/<user_secret>/api", docs_ui='elements', json_errors=False, enable_openapi=True)
# app = Flask(__name__, static_url_path="/<proxy_path>/static/", instance_relative_config=True)
app.wsgi_app = ProxyFix(
app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1
)
app.servers = {
'name': 'current',
'url': '',
}
app.info = {
'description': 'Hiddify is a free and open source software. It is as it is.',
'termsOfService': 'http://hiddify.com',
'contact': {
'name': 'API Support',
'url': 'http://www.hiddify.com/support',
'email': 'panel@hiddify.com'
},
'license': {
'name': 'Creative Commons Zero v1.0 Universal',
'url': 'https://github.com/hiddify/Hiddify-Manager/blob/main/LICENSE'
}
}

for c, v in dotenv_values(os.environ.get("HIDDIFY_CFG_PATH", 'app.cfg')).items():
if v.isdecimal():
v = int(v)
Expand All @@ -30,12 +49,15 @@ def create_app(cli=False, **config):

app.jinja_env.line_statement_prefix = '%'
app.jinja_env.filters['b64encode'] = hiddify.do_base_64

app.view_functions['admin.static']={}#fix bug in apiflask
app.is_cli = cli
flask_bootstrap.Bootstrap4(app)

hiddifypanel.panel.database.init_app(app)
with app.app_context():
# hiddifypanel.panel.database.init_migration(app)
# hiddifypanel.panel.database.migrate()
# hiddifypanel.panel.database.upgrade()
init_db()

hiddifypanel.panel.common.init_app(app)
Expand Down
3 changes: 2 additions & 1 deletion hiddifypanel/panel/admin/Dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import os
import re

from flask import render_template, url_for, request, jsonify, g, redirect, abort
from flask import render_template, url_for, request, jsonify, g, redirect
from apiflask import abort
from flask_babelex import lazy_gettext as _
from flask_classful import FlaskView, route

Expand Down
3 changes: 2 additions & 1 deletion hiddifypanel/panel/admin/ProxyAdmin.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@


import re
from flask import render_template, current_app, Markup, url_for, abort
from flask import render_template, current_app, Markup, url_for
from apiflask import abort
from hiddifypanel.panel.hiddify import flash
from hiddifypanel.models import User, Domain, DomainType, StrConfig, ConfigEnum, get_hconfigs
from hiddifypanel.panel.database import db
Expand Down
3 changes: 2 additions & 1 deletion hiddifypanel/panel/admin/SettingAdmin.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
from hiddifypanel.panel.hiddify import get_random_domains

import re
from flask import render_template, current_app, Markup, url_for, abort, g
from flask import render_template, current_app, Markup, url_for, g
from apiflask import abort
from hiddifypanel.panel.hiddify import flash
from hiddifypanel.models import *
from hiddifypanel.panel.database import db
Expand Down
3 changes: 2 additions & 1 deletion hiddifypanel/panel/admin/UserAdmin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from hiddifypanel.panel.database import db
import datetime
from hiddifypanel.models import *
from flask import Markup, g, request, url_for, abort
from flask import Markup, g, request, url_for
from apiflask import abort
from wtforms.validators import Regexp, ValidationError
import re
import uuid
Expand Down
3 changes: 2 additions & 1 deletion hiddifypanel/panel/commercial/restapi/v1/resources.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from flask import abort, jsonify, request
from flask import jsonify, request
from apiflask import abort
from flask_restful import Resource
# from flask_simplelogin import login_required
import datetime
Expand Down
3 changes: 2 additions & 1 deletion hiddifypanel/panel/commercial/restapi/v1/tgbot.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import time
import telebot
from flask import abort, request
from flask import request
from apiflask import abort
from flask_restful import Resource

from hiddifypanel.models import *
Expand Down
3 changes: 2 additions & 1 deletion hiddifypanel/panel/commercial/restapi/v1/tgmsg.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from flask import abort, jsonify, request
from flask import jsonify, request
from apiflask import abort
from flask_restful import Resource
# from flask_simplelogin import login_required
import datetime
Expand Down
75 changes: 75 additions & 0 deletions hiddifypanel/panel/commercial/restapi/v2/admin/DTO.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from apiflask import Schema
from apiflask.fields import Integer, String, UUID, Boolean, Enum, Float, Date, Time,Dict
from hiddifypanel.models import AdminMode,UserMode,Lang

class AdminSchema(Schema):
name = String(required=True, description='The name of the admin')
comment = String(required=False, description='A comment related to the admin')
uuid = UUID(required=True, description='The unique identifier for the admin')
mode = Enum(AdminMode, required=True, description='The mode for the admin')
can_add_admin = Boolean(required=True, description='Whether the admin can add other admins')
parent_admin_uuid = UUID(description='The unique identifier for the parent admin', allow_none=True,
# validate=OneOf([p.uuid for p in AdminUser.query.all()])
)
telegram_id = Integer(required=True, description='The Telegram ID associated with the admin')
lang = Enum(Lang,required=True)

class ServerStatus(Schema):
stats = Dict()
usage_history = Dict()


class UserSchema(Schema):
uuid = UUID(required=True, description="Unique identifier for the user")
name = String(required=True, description="Name of the user")

usage_limit_GB = Float(
required=False,
description="The data usage limit for the user in gigabytes"
)
package_days = Integer(
required=False,
description="The number of days in the user's package"
)
mode = Enum(UserMode,
required=False,
description="The mode of the user's account, which dictates access level or type"
)
last_online = Time(
format="%Y-%m-%d %H:%M:%S",
description="The last time the user was online, converted to a JSON-friendly format"
)
start_date = Date(
format='%Y-%m-%d',
description="The start date of the user's package, in a JSON-friendly format"
)
current_usage_GB = Float(
required=False,
description="The current data usage of the user in gigabytes"
)
last_reset_time = Date(
format='%Y-%m-%d',
description="The last time the user's data usage was reset, in a JSON-friendly format"
)
comment = String(
missing=None,
description="An optional comment about the user"
)
added_by_uuid = UUID(
required=True,
description="UUID of the admin who added this user",
# validate=OneOf([p.uuid for p in AdminUser.query.all()])
)
telegram_id = Integer(
required=False,
description="The Telegram ID associated with the user"
)
ed25519_private_key = String(
required=False,
description="If empty, it will be created automatically, The user's private key using the Ed25519 algorithm"
)
ed25519_public_key = String(
required=False,
description="If empty, it will be created automatically,The user's public key using the Ed25519 algorithm"
)

4 changes: 3 additions & 1 deletion hiddifypanel/panel/commercial/restapi/v2/admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
def init_app(app):

with app.app_context():
from .admin_user import AdminUsersApi, AdminUserApi
from .admin_user import AdminUsersApi, AdminUserApi,AdminInfoApi,AdminServerStatus
bp.add_url_rule('/me/',view_func=AdminInfoApi)
bp.add_url_rule('/server_status/',view_func=AdminServerStatus)
bp.add_url_rule('/admin_user/', view_func=AdminUsersApi)
bp.add_url_rule('/admin_user/<uuid:uuid>', view_func=AdminUserApi)

Expand Down
64 changes: 41 additions & 23 deletions hiddifypanel/panel/commercial/restapi/v2/admin/admin_user.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,48 @@
from flask import abort, jsonify, request
from flask import jsonify, request
from flask_restful import Resource
# from flask_simplelogin import login_required
import datetime
from hiddifypanel.models import *
from urllib.parse import urlparse
from hiddifypanel.panel import hiddify
from hiddifypanel.drivers import user_driver

from flask.views import MethodView

from flask import current_app as app
from apiflask import APIFlask, Schema, abort
from apiflask.validators import Length, OneOf
from apiflask.fields import Integer, String, UUID, Boolean, Enum, Float, Date, Time
from flask import g
from apiflask import abort

from hiddifypanel.models import *
from hiddifypanel.panel.commercial.restapi.v2.admin.DTO import *


class AdminDTO(Schema):
name = String(required=True, description='The name of the admin')
comment = String(required=False, description='A comment related to the admin')
uuid = UUID(required=True, description='The unique identifier for the admin')
mode = Enum(AdminMode, required=True, description='The mode for the admin')
can_add_admin = Boolean(required=True, description='Whether the admin can add other admins')
parent_admin_uuid = UUID(description='The unique identifier for the parent admin', allow_none=True,
# validate=OneOf([p.uuid for p in AdminUser.query.all()])
)
telegram_id = Integer(required=True, description='The Telegram ID associated with the admin')


class AdminInfoApi(MethodView):
decorators = [hiddify.super_admin]
@app.output(AdminSchema)
def get(self):
# in this case g.user_uuid is equal to admin uuid
admin_uuid = g.user_uuid
admin = get_admin_user_db(admin_uuid) or abort(404, "user not found")

dto = AdminSchema()
dto.name = admin.name
dto.comment = admin.comment
dto.uuid = admin.uuid
dto.mode = admin.mode
dto.can_add_admin = admin.can_add_admin
dto.parent_admin_uuid = AdminUser.query.filter(AdminUser.id == admin.parent_admin_id).first().uuid or 'None'
dto.telegram_id = admin.telegram_id
dto.lang = Lang(hconfig(ConfigEnum.admin_lang))
return dto
class AdminUsersApi(MethodView):
decorators = [hiddify.super_admin]

@app.output(AdminDTO(many=True))
@app.output(AdminSchema(many=True))
def get(self):
admins = AdminUser.query.all() or abort(502, "WTF!")
return [admin.to_dict() for admin in admins]

@app.input(AdminDTO, arg_name='data')
@app.output(AdminDTO)
@app.input(AdminSchema, arg_name='data')
@app.output(AdminSchema)
def put(self, data):
# data = request.json
# uuid = data.get('uuid') or abort(422, "Parameter issue: 'uuid'")
Expand All @@ -50,13 +54,13 @@ def put(self, data):
class AdminUserApi(MethodView):
decorators = [hiddify.super_admin]

@app.output(AdminDTO)
@app.output(AdminSchema)
def get(self, uuid):

admin = get_admin_user_db(uuid) or abort(404, "user not found")
return admin.to_dict()

@app.input(AdminDTO, arg_name='data')
@app.input(AdminSchema, arg_name='data')
def patch(self, uuid, data):
data['uuid'] = uuid
hiddify.add_or_update_admin(**data)
Expand All @@ -66,3 +70,17 @@ def delete(self, uuid):
admin = get_admin_user_db(uuid) or abort(404, "admin not found")
admin.remove()
return {'status': 200, 'msg': 'ok'}

class AdminServerStatus(MethodView):
decorators = [hiddify.super_admin]

@app.output(ServerStatus)
def get(self):
dto = ServerStatus()
dto.stats = {
'system': hiddify.system_stats(),
'top5': hiddify.top_processes()
}
admin_id = request.args.get("admin_id") or g.admin.id
dto.usage_history = get_daily_usage_stats(admin_id)
return dto
Loading