Merge branch 'main' into feat/rag-2

This commit is contained in:
twwu
2025-08-25 15:30:18 +08:00
301 changed files with 6189 additions and 2763 deletions

View File

@ -84,7 +84,6 @@ from .datasets import (
external,
hit_testing,
metadata,
upload_file,
website,
)
from .datasets.rag_pipeline import (

View File

@ -1,7 +1,7 @@
from functools import wraps
from flask import request
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from sqlalchemy import select
from sqlalchemy.orm import Session
from werkzeug.exceptions import NotFound, Unauthorized

View File

@ -1,8 +1,8 @@
from typing import Any, Optional
import flask_restful
import flask_restx
from flask_login import current_user
from flask_restful import Resource, fields, marshal_with
from flask_restx import Resource, fields, marshal_with
from sqlalchemy import select
from sqlalchemy.orm import Session
from werkzeug.exceptions import Forbidden
@ -40,7 +40,7 @@ def _get_resource(resource_id, tenant_id, resource_model):
).scalar_one_or_none()
if resource is None:
flask_restful.abort(404, message=f"{resource_model.__name__} not found.")
flask_restx.abort(404, message=f"{resource_model.__name__} not found.")
return resource
@ -81,7 +81,7 @@ class BaseApiKeyListResource(Resource):
)
if current_key_count >= self.max_keys:
flask_restful.abort(
flask_restx.abort(
400,
message=f"Cannot create more than {self.max_keys} API keys for this resource type.",
code="max_keys_exceeded",
@ -126,7 +126,7 @@ class BaseApiKeyResource(Resource):
)
if key is None:
flask_restful.abort(404, message="API key not found")
flask_restx.abort(404, message="API key not found")
db.session.query(ApiToken).where(ApiToken.id == api_key_id).delete()
db.session.commit()

View File

@ -1,4 +1,4 @@
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from controllers.console import api
from controllers.console.wraps import account_initialization_required, setup_required

View File

@ -1,4 +1,4 @@
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from controllers.console import api
from controllers.console.app.wraps import get_app_model

View File

@ -2,7 +2,7 @@ from typing import Literal
from flask import request
from flask_login import current_user
from flask_restful import Resource, marshal, marshal_with, reqparse
from flask_restx import Resource, marshal, marshal_with, reqparse
from werkzeug.exceptions import Forbidden
from controllers.common.errors import NoFileUploadedError, TooManyFilesError

View File

@ -2,7 +2,7 @@ import uuid
from typing import cast
from flask_login import current_user
from flask_restful import Resource, inputs, marshal, marshal_with, reqparse
from flask_restx import Resource, inputs, marshal, marshal_with, reqparse
from sqlalchemy import select
from sqlalchemy.orm import Session
from werkzeug.exceptions import BadRequest, Forbidden, abort

View File

@ -1,7 +1,7 @@
from typing import cast
from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse
from sqlalchemy.orm import Session
from werkzeug.exceptions import Forbidden

View File

@ -1,7 +1,7 @@
import logging
from flask import request
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import InternalServerError
import services

View File

@ -2,7 +2,7 @@ import logging
import flask_login
from flask import request
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import InternalServerError, NotFound
import services

View File

@ -2,8 +2,8 @@ from datetime import datetime
import pytz # pip install pytz
from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restful.inputs import int_range
from flask_restx import Resource, marshal_with, reqparse
from flask_restx.inputs import int_range
from sqlalchemy import func, or_
from sqlalchemy.orm import joinedload
from werkzeug.exceptions import Forbidden, NotFound
@ -24,6 +24,8 @@ from libs.helper import DatetimeString
from libs.login import login_required
from models import Conversation, EndUser, Message, MessageAnnotation
from models.model import AppMode
from services.conversation_service import ConversationService
from services.errors.conversation import ConversationNotExistsError
class CompletionConversationApi(Resource):
@ -46,7 +48,9 @@ class CompletionConversationApi(Resource):
parser.add_argument("limit", type=int_range(1, 100), default=20, location="args")
args = parser.parse_args()
query = db.select(Conversation).where(Conversation.app_id == app_model.id, Conversation.mode == "completion")
query = db.select(Conversation).where(
Conversation.app_id == app_model.id, Conversation.mode == "completion", Conversation.is_deleted.is_(False)
)
if args["keyword"]:
query = query.join(Message, Message.conversation_id == Conversation.id).where(
@ -119,18 +123,11 @@ class CompletionConversationDetailApi(Resource):
raise Forbidden()
conversation_id = str(conversation_id)
conversation = (
db.session.query(Conversation)
.where(Conversation.id == conversation_id, Conversation.app_id == app_model.id)
.first()
)
if not conversation:
try:
ConversationService.delete(app_model, conversation_id, current_user)
except ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
conversation.is_deleted = True
db.session.commit()
return {"result": "success"}, 204
@ -171,7 +168,7 @@ class ChatConversationApi(Resource):
.subquery()
)
query = db.select(Conversation).where(Conversation.app_id == app_model.id)
query = db.select(Conversation).where(Conversation.app_id == app_model.id, Conversation.is_deleted.is_(False))
if args["keyword"]:
keyword_filter = f"%{args['keyword']}%"
@ -284,18 +281,11 @@ class ChatConversationDetailApi(Resource):
raise Forbidden()
conversation_id = str(conversation_id)
conversation = (
db.session.query(Conversation)
.where(Conversation.id == conversation_id, Conversation.app_id == app_model.id)
.first()
)
if not conversation:
try:
ConversationService.delete(app_model, conversation_id, current_user)
except ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
conversation.is_deleted = True
db.session.commit()
return {"result": "success"}, 204

View File

@ -1,4 +1,4 @@
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse
from sqlalchemy import select
from sqlalchemy.orm import Session

View File

@ -1,7 +1,7 @@
from collections.abc import Sequence
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from controllers.console import api
from controllers.console.app.error import (

View File

@ -2,7 +2,7 @@ import json
from enum import StrEnum
from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse
from werkzeug.exceptions import NotFound
from controllers.console import api

View File

@ -1,8 +1,8 @@
import logging
from flask_login import current_user
from flask_restful import Resource, fields, marshal_with, reqparse
from flask_restful.inputs import int_range
from flask_restx import Resource, fields, marshal_with, reqparse
from flask_restx.inputs import int_range
from werkzeug.exceptions import Forbidden, InternalServerError, NotFound
from controllers.console import api

View File

@ -3,7 +3,7 @@ from typing import cast
from flask import request
from flask_login import current_user
from flask_restful import Resource
from flask_restx import Resource
from controllers.console import api
from controllers.console.app.wraps import get_app_model

View File

@ -1,4 +1,4 @@
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import BadRequest
from controllers.console import api

View File

@ -1,5 +1,5 @@
from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse
from werkzeug.exceptions import Forbidden, NotFound
from constants.languages import supported_language

View File

@ -5,7 +5,7 @@ import pytz
import sqlalchemy as sa
from flask import jsonify
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from controllers.console import api
from controllers.console.app.wraps import get_app_model

View File

@ -4,7 +4,7 @@ from collections.abc import Sequence
from typing import cast
from flask import abort, request
from flask_restful import Resource, inputs, marshal_with, reqparse
from flask_restx import Resource, inputs, marshal_with, reqparse
from sqlalchemy.orm import Session
from werkzeug.exceptions import Forbidden, InternalServerError, NotFound

View File

@ -1,6 +1,6 @@
from dateutil.parser import isoparse
from flask_restful import Resource, marshal_with, reqparse
from flask_restful.inputs import int_range
from flask_restx import Resource, marshal_with, reqparse
from flask_restx.inputs import int_range
from sqlalchemy.orm import Session
from controllers.console import api

View File

@ -2,7 +2,7 @@ import logging
from typing import Any, NoReturn
from flask import Response
from flask_restful import Resource, fields, inputs, marshal, marshal_with, reqparse
from flask_restx import Resource, fields, inputs, marshal, marshal_with, reqparse
from sqlalchemy.orm import Session
from werkzeug.exceptions import Forbidden

View File

@ -1,8 +1,8 @@
from typing import cast
from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restful.inputs import int_range
from flask_restx import Resource, marshal_with, reqparse
from flask_restx.inputs import int_range
from controllers.console import api
from controllers.console.app.wraps import get_app_model

View File

@ -5,7 +5,7 @@ import pytz
import sqlalchemy as sa
from flask import jsonify
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from controllers.console import api
from controllers.console.app.wraps import get_app_model

View File

@ -1,5 +1,5 @@
from flask import request
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from constants.languages import supported_language
from controllers.console import api

View File

@ -1,5 +1,5 @@
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import Forbidden
from controllers.console import api

View File

@ -3,7 +3,7 @@ import logging
import requests
from flask import current_app, redirect, request
from flask_login import current_user
from flask_restful import Resource
from flask_restx import Resource
from werkzeug.exceptions import Forbidden
from configs import dify_config

View File

@ -2,7 +2,7 @@ import base64
import secrets
from flask import request
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from sqlalchemy import select
from sqlalchemy.orm import Session

View File

@ -2,7 +2,7 @@ from typing import cast
import flask_login
from flask import request
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
import services
from configs import dify_config
@ -221,7 +221,7 @@ class EmailCodeLoginApi(Resource):
email=user_email, name=user_email, interface_language=languages[0]
)
except WorkSpaceNotAllowedCreateError:
return NotAllowedCreateWorkspace()
raise NotAllowedCreateWorkspace()
except AccountRegisterError as are:
raise AccountInFreezeError()
except WorkspacesLimitExceededError:

View File

@ -3,7 +3,7 @@ from typing import Optional
import requests
from flask import current_app, redirect, request
from flask_restful import Resource
from flask_restx import Resource
from sqlalchemy import select
from sqlalchemy.orm import Session
from werkzeug.exceptions import Unauthorized

View File

@ -1,5 +1,5 @@
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from controllers.console import api
from controllers.console.wraps import account_initialization_required, only_edition_cloud, setup_required

View File

@ -1,6 +1,6 @@
from flask import request
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from libs.helper import extract_remote_ip
from libs.login import login_required

View File

@ -4,7 +4,7 @@ from typing import cast
from flask import request
from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse
from sqlalchemy import select
from sqlalchemy.orm import Session
from werkzeug.exceptions import NotFound

View File

@ -1,7 +1,7 @@
import flask_restful
import flask_restx
from flask import request
from flask_login import current_user
from flask_restful import Resource, marshal, marshal_with, reqparse
from flask_restx import Resource, marshal, marshal_with, reqparse
from werkzeug.exceptions import Forbidden, NotFound
import services
@ -600,7 +600,7 @@ class DatasetApiKeyApi(Resource):
)
if current_key_count >= self.max_keys:
flask_restful.abort(
flask_restx.abort(
400,
message=f"Cannot create more than {self.max_keys} API keys for this resource type.",
code="max_keys_exceeded",
@ -640,7 +640,7 @@ class DatasetApiDeleteApi(Resource):
)
if key is None:
flask_restful.abort(404, message="API key not found")
flask_restx.abort(404, message="API key not found")
db.session.query(ApiToken).where(ApiToken.id == api_key_id).delete()
db.session.commit()

View File

@ -5,7 +5,7 @@ from typing import Literal, cast
from flask import request
from flask_login import current_user
from flask_restful import Resource, marshal, marshal_with, reqparse
from flask_restx import Resource, marshal, marshal_with, reqparse
from sqlalchemy import asc, desc, select
from werkzeug.exceptions import Forbidden, NotFound

View File

@ -2,7 +2,7 @@ import uuid
from flask import request
from flask_login import current_user
from flask_restful import Resource, marshal, reqparse
from flask_restx import Resource, marshal, reqparse
from sqlalchemy import select
from werkzeug.exceptions import Forbidden, NotFound
@ -584,7 +584,12 @@ class ChildChunkUpdateApi(Resource):
child_chunk_id = str(child_chunk_id)
child_chunk = (
db.session.query(ChildChunk)
.where(ChildChunk.id == str(child_chunk_id), ChildChunk.tenant_id == current_user.current_tenant_id)
.where(
ChildChunk.id == str(child_chunk_id),
ChildChunk.tenant_id == current_user.current_tenant_id,
ChildChunk.segment_id == segment.id,
ChildChunk.document_id == document_id,
)
.first()
)
if not child_chunk:
@ -633,7 +638,12 @@ class ChildChunkUpdateApi(Resource):
child_chunk_id = str(child_chunk_id)
child_chunk = (
db.session.query(ChildChunk)
.where(ChildChunk.id == str(child_chunk_id), ChildChunk.tenant_id == current_user.current_tenant_id)
.where(
ChildChunk.id == str(child_chunk_id),
ChildChunk.tenant_id == current_user.current_tenant_id,
ChildChunk.segment_id == segment.id,
ChildChunk.document_id == document_id,
)
.first()
)
if not child_chunk:

View File

@ -1,6 +1,6 @@
from flask import request
from flask_login import current_user
from flask_restful import Resource, marshal, reqparse
from flask_restx import Resource, marshal, reqparse
from werkzeug.exceptions import Forbidden, InternalServerError, NotFound
import services

View File

@ -1,4 +1,4 @@
from flask_restful import Resource
from flask_restx import Resource
from controllers.console import api
from controllers.console.datasets.hit_testing_base import DatasetsHitTestingBase

View File

@ -1,7 +1,7 @@
import logging
from flask_login import current_user
from flask_restful import marshal, reqparse
from flask_restx import marshal, reqparse
from werkzeug.exceptions import Forbidden, InternalServerError, NotFound
import services.dataset_service

View File

@ -1,7 +1,7 @@
from typing import Literal
from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse
from werkzeug.exceptions import NotFound
from controllers.console import api

View File

@ -1,62 +0,0 @@
from flask_login import current_user
from flask_restful import Resource
from werkzeug.exceptions import NotFound
from controllers.console import api
from controllers.console.wraps import (
account_initialization_required,
setup_required,
)
from core.file import helpers as file_helpers
from extensions.ext_database import db
from models.dataset import Dataset
from models.model import UploadFile
from services.dataset_service import DocumentService
class UploadFileApi(Resource):
@setup_required
@account_initialization_required
def get(self, dataset_id, document_id):
"""Get upload file."""
# check dataset
dataset_id = str(dataset_id)
dataset = (
db.session.query(Dataset)
.filter(Dataset.tenant_id == current_user.current_tenant_id, Dataset.id == dataset_id)
.first()
)
if not dataset:
raise NotFound("Dataset not found.")
# check document
document_id = str(document_id)
document = DocumentService.get_document(dataset.id, document_id)
if not document:
raise NotFound("Document not found.")
# check upload file
if document.data_source_type != "upload_file":
raise ValueError(f"Document data source type ({document.data_source_type}) is not upload_file.")
data_source_info = document.data_source_info_dict
if data_source_info and "upload_file_id" in data_source_info:
file_id = data_source_info["upload_file_id"]
upload_file = db.session.query(UploadFile).where(UploadFile.id == file_id).first()
if not upload_file:
raise NotFound("UploadFile not found.")
else:
raise ValueError("Upload file id not found in document data source info.")
url = file_helpers.get_signed_file_url(upload_file_id=upload_file.id)
return {
"id": upload_file.id,
"name": upload_file.name,
"size": upload_file.size,
"extension": upload_file.extension,
"url": url,
"download_url": f"{url}&as_attachment=true",
"mime_type": upload_file.mime_type,
"created_by": upload_file.created_by,
"created_at": upload_file.created_at.timestamp(),
}, 200
api.add_resource(UploadFileApi, "/datasets/<uuid:dataset_id>/documents/<uuid:document_id>/upload-file")

View File

@ -1,4 +1,4 @@
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from controllers.console import api
from controllers.console.datasets.error import WebsiteCrawlError

View File

@ -65,7 +65,7 @@ class ChatAudioApi(InstalledAppResource):
class ChatTextApi(InstalledAppResource):
def post(self, installed_app):
from flask_restful import reqparse
from flask_restx import reqparse
app_model = installed_app.app
try:

View File

@ -1,7 +1,7 @@
import logging
from flask_login import current_user
from flask_restful import reqparse
from flask_restx import reqparse
from werkzeug.exceptions import InternalServerError, NotFound
import services

View File

@ -1,6 +1,6 @@
from flask_login import current_user
from flask_restful import marshal_with, reqparse
from flask_restful.inputs import int_range
from flask_restx import marshal_with, reqparse
from flask_restx.inputs import int_range
from sqlalchemy.orm import Session
from werkzeug.exceptions import NotFound

View File

@ -3,7 +3,7 @@ from typing import Any
from flask import request
from flask_login import current_user
from flask_restful import Resource, inputs, marshal_with, reqparse
from flask_restx import Resource, inputs, marshal_with, reqparse
from sqlalchemy import and_
from werkzeug.exceptions import BadRequest, Forbidden, NotFound

View File

@ -1,8 +1,8 @@
import logging
from flask_login import current_user
from flask_restful import marshal_with, reqparse
from flask_restful.inputs import int_range
from flask_restx import marshal_with, reqparse
from flask_restx.inputs import int_range
from werkzeug.exceptions import InternalServerError, NotFound
from controllers.console.app.error import (

View File

@ -1,4 +1,4 @@
from flask_restful import marshal_with
from flask_restx import marshal_with
from controllers.common import fields
from controllers.console import api

View File

@ -1,5 +1,5 @@
from flask_login import current_user
from flask_restful import Resource, fields, marshal_with, reqparse
from flask_restx import Resource, fields, marshal_with, reqparse
from constants.languages import languages
from controllers.console import api

View File

@ -1,6 +1,6 @@
from flask_login import current_user
from flask_restful import fields, marshal_with, reqparse
from flask_restful.inputs import int_range
from flask_restx import fields, marshal_with, reqparse
from flask_restx.inputs import int_range
from werkzeug.exceptions import NotFound
from controllers.console import api

View File

@ -1,6 +1,6 @@
import logging
from flask_restful import reqparse
from flask_restx import reqparse
from werkzeug.exceptions import InternalServerError
from controllers.console.app.error import (

View File

@ -1,7 +1,7 @@
from functools import wraps
from flask_login import current_user
from flask_restful import Resource
from flask_restx import Resource
from werkzeug.exceptions import NotFound
from controllers.console.explore.error import AppAccessDeniedError

View File

@ -1,5 +1,5 @@
from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse
from constants import HIDDEN_VALUE
from controllers.console import api

View File

@ -1,5 +1,5 @@
from flask_login import current_user
from flask_restful import Resource
from flask_restx import Resource
from libs.login import login_required
from services.feature_service import FeatureService

View File

@ -2,7 +2,7 @@ from typing import Literal
from flask import request
from flask_login import current_user
from flask_restful import Resource, marshal_with
from flask_restx import Resource, marshal_with
from werkzeug.exceptions import Forbidden
import services

View File

@ -1,7 +1,7 @@
import os
from flask import session
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from sqlalchemy import select
from sqlalchemy.orm import Session

View File

@ -1,4 +1,4 @@
from flask_restful import Resource
from flask_restx import Resource
from controllers.console import api

View File

@ -3,7 +3,7 @@ from typing import cast
import httpx
from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse
import services
from controllers.common import helpers

View File

@ -1,5 +1,5 @@
from flask import request
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from configs import dify_config
from libs.helper import StrLen, email, extract_remote_ip

View File

@ -1,11 +1,11 @@
from flask import request
from flask_login import current_user
from flask_restful import Resource, marshal_with, reqparse
from flask_restx import Resource, marshal_with, reqparse
from werkzeug.exceptions import Forbidden
from controllers.console import api
from controllers.console.wraps import account_initialization_required, setup_required
from fields.tag_fields import tag_fields
from fields.tag_fields import dataset_tag_fields
from libs.login import login_required
from models.model import Tag
from services.tag_service import TagService
@ -21,7 +21,7 @@ class TagListApi(Resource):
@setup_required
@login_required
@account_initialization_required
@marshal_with(tag_fields)
@marshal_with(dataset_tag_fields)
def get(self):
tag_type = request.args.get("type", type=str, default="")
keyword = request.args.get("keyword", default=None, type=str)

View File

@ -2,7 +2,7 @@ import json
import logging
import requests
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from packaging import version
from configs import dify_config

View File

@ -3,7 +3,7 @@ from datetime import datetime
import pytz
from flask import request
from flask_login import current_user
from flask_restful import Resource, fields, marshal_with, reqparse
from flask_restx import Resource, fields, marshal_with, reqparse
from sqlalchemy import select
from sqlalchemy.orm import Session

View File

@ -1,5 +1,5 @@
from flask_login import current_user
from flask_restful import Resource
from flask_restx import Resource
from controllers.console import api
from controllers.console.wraps import account_initialization_required, setup_required

View File

@ -1,5 +1,5 @@
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import Forbidden
from controllers.console import api

View File

@ -1,4 +1,4 @@
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import Forbidden
from controllers.console import api

View File

@ -2,7 +2,7 @@ from urllib import parse
from flask import request
from flask_login import current_user
from flask_restful import Resource, abort, marshal_with, reqparse
from flask_restx import Resource, abort, marshal_with, reqparse
import services
from configs import dify_config

View File

@ -2,7 +2,7 @@ import io
from flask import send_file
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import Forbidden
from controllers.console import api

View File

@ -1,7 +1,7 @@
import logging
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import Forbidden
from controllers.console import api

View File

@ -2,7 +2,7 @@ import io
from flask import request, send_file
from flask_login import current_user
from flask_restful import Resource, reqparse
from flask_restx import Resource, reqparse
from werkzeug.exceptions import Forbidden
from configs import dify_config

View File

@ -3,7 +3,7 @@ from urllib.parse import urlparse
from flask import make_response, redirect, request, send_file
from flask_login import current_user
from flask_restful import (
from flask_restx import (
Resource,
reqparse,
)

View File

@ -2,7 +2,7 @@ import logging
from flask import request
from flask_login import current_user
from flask_restful import Resource, fields, inputs, marshal, marshal_with, reqparse
from flask_restx import Resource, fields, inputs, marshal, marshal_with, reqparse
from sqlalchemy import select
from werkzeug.exceptions import Unauthorized