explore.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. # -*- coding:utf-8 -*-
  2. from datetime import datetime
  3. from flask_login import login_required, current_user
  4. from flask_restful import Resource, reqparse, fields, marshal_with, abort, inputs
  5. from sqlalchemy import and_
  6. from controllers.console import api
  7. from extensions.ext_database import db
  8. from models.model import Tenant, App, InstalledApp, RecommendedApp
  9. from services.account_service import TenantService
  10. app_fields = {
  11. 'id': fields.String,
  12. 'name': fields.String,
  13. 'mode': fields.String,
  14. 'icon': fields.String,
  15. 'icon_background': fields.String
  16. }
  17. installed_app_fields = {
  18. 'id': fields.String,
  19. 'app': fields.Nested(app_fields, attribute='app'),
  20. 'app_owner_tenant_id': fields.String,
  21. 'is_pinned': fields.Boolean,
  22. 'last_used_at': fields.DateTime,
  23. 'editable': fields.Boolean
  24. }
  25. installed_app_list_fields = {
  26. 'installed_apps': fields.List(fields.Nested(installed_app_fields))
  27. }
  28. recommended_app_fields = {
  29. 'app': fields.Nested(app_fields, attribute='app'),
  30. 'app_id': fields.String,
  31. 'description': fields.String(attribute='description'),
  32. 'copyright': fields.String,
  33. 'privacy_policy': fields.String,
  34. 'category': fields.String,
  35. 'position': fields.Integer,
  36. 'is_listed': fields.Boolean,
  37. 'install_count': fields.Integer,
  38. 'installed': fields.Boolean,
  39. 'editable': fields.Boolean
  40. }
  41. recommended_app_list_fields = {
  42. 'recommended_apps': fields.List(fields.Nested(recommended_app_fields)),
  43. 'categories': fields.List(fields.String)
  44. }
  45. class InstalledAppsListResource(Resource):
  46. @login_required
  47. @marshal_with(installed_app_list_fields)
  48. def get(self):
  49. current_tenant_id = Tenant.query.first().id
  50. installed_apps = db.session.query(InstalledApp).filter(
  51. InstalledApp.tenant_id == current_tenant_id
  52. ).all()
  53. current_user.role = TenantService.get_user_role(current_user, current_user.current_tenant)
  54. installed_apps = [
  55. {
  56. **installed_app,
  57. "editable": current_user.role in ["owner", "admin"],
  58. }
  59. for installed_app in installed_apps
  60. ]
  61. installed_apps.sort(key=lambda app: (-app.is_pinned, app.last_used_at))
  62. return {'installed_apps': installed_apps}
  63. @login_required
  64. def post(self):
  65. parser = reqparse.RequestParser()
  66. parser.add_argument('app_id', type=str, required=True, help='Invalid app_id')
  67. args = parser.parse_args()
  68. current_tenant_id = Tenant.query.first().id
  69. app = App.query.get(args['app_id'])
  70. if app is None:
  71. abort(404, message='App not found')
  72. recommended_app = RecommendedApp.query.filter(RecommendedApp.app_id == args['app_id']).first()
  73. if recommended_app is None:
  74. abort(404, message='App not found')
  75. if not app.is_public:
  76. abort(403, message="You can't install a non-public app")
  77. installed_app = InstalledApp.query.filter(and_(
  78. InstalledApp.app_id == args['app_id'],
  79. InstalledApp.tenant_id == current_tenant_id
  80. )).first()
  81. if installed_app is None:
  82. # todo: position
  83. recommended_app.install_count += 1
  84. new_installed_app = InstalledApp(
  85. app_id=args['app_id'],
  86. tenant_id=current_tenant_id,
  87. is_pinned=False,
  88. last_used_at=datetime.utcnow()
  89. )
  90. db.session.add(new_installed_app)
  91. db.session.commit()
  92. return {'message': 'App installed successfully'}
  93. class InstalledAppResource(Resource):
  94. @login_required
  95. def delete(self, installed_app_id):
  96. installed_app = InstalledApp.query.filter(and_(
  97. InstalledApp.id == str(installed_app_id),
  98. InstalledApp.tenant_id == current_user.current_tenant_id
  99. )).first()
  100. if installed_app is None:
  101. abort(404, message='App not found')
  102. if installed_app.app_owner_tenant_id == current_user.current_tenant_id:
  103. abort(400, message="You can't uninstall an app owned by the current tenant")
  104. db.session.delete(installed_app)
  105. db.session.commit()
  106. return {'result': 'success', 'message': 'App uninstalled successfully'}
  107. @login_required
  108. def patch(self, installed_app_id):
  109. parser = reqparse.RequestParser()
  110. parser.add_argument('is_pinned', type=inputs.boolean)
  111. args = parser.parse_args()
  112. current_tenant_id = Tenant.query.first().id
  113. installed_app = InstalledApp.query.filter(and_(
  114. InstalledApp.id == str(installed_app_id),
  115. InstalledApp.tenant_id == current_tenant_id
  116. )).first()
  117. if installed_app is None:
  118. abort(404, message='Installed app not found')
  119. commit_args = False
  120. if 'is_pinned' in args:
  121. installed_app.is_pinned = args['is_pinned']
  122. commit_args = True
  123. if commit_args:
  124. db.session.commit()
  125. return {'result': 'success', 'message': 'App info updated successfully'}
  126. class RecommendedAppsResource(Resource):
  127. @login_required
  128. @marshal_with(recommended_app_list_fields)
  129. def get(self):
  130. recommended_apps = db.session.query(RecommendedApp).filter(
  131. RecommendedApp.is_listed == True
  132. ).all()
  133. categories = set()
  134. current_user.role = TenantService.get_user_role(current_user, current_user.current_tenant)
  135. recommended_apps_result = []
  136. for recommended_app in recommended_apps:
  137. installed = db.session.query(InstalledApp).filter(
  138. and_(
  139. InstalledApp.app_id == recommended_app.app_id,
  140. InstalledApp.tenant_id == current_user.current_tenant_id
  141. )
  142. ).first() is not None
  143. language_prefix = current_user.interface_language.split('-')[0]
  144. desc = None
  145. if recommended_app.description:
  146. if language_prefix in recommended_app.description:
  147. desc = recommended_app.description[language_prefix]
  148. elif 'en' in recommended_app.description:
  149. desc = recommended_app.description['en']
  150. recommended_app_result = {
  151. 'id': recommended_app.id,
  152. 'app': recommended_app.app,
  153. 'app_id': recommended_app.app_id,
  154. 'description': desc,
  155. 'copyright': recommended_app.copyright,
  156. 'privacy_policy': recommended_app.privacy_policy,
  157. 'category': recommended_app.category,
  158. 'position': recommended_app.position,
  159. 'is_listed': recommended_app.is_listed,
  160. 'install_count': recommended_app.install_count,
  161. 'installed': installed,
  162. 'editable': current_user.role in ['owner', 'admin'],
  163. }
  164. recommended_apps_result.append(recommended_app_result)
  165. categories.add(recommended_app.category) # add category to categories
  166. return {'recommended_apps': recommended_apps_result, 'categories': list(categories)}
  167. api.add_resource(InstalledAppsListResource, '/installed-apps')
  168. api.add_resource(InstalledAppResource, '/installed-apps/<uuid:installed_app_id>')
  169. api.add_resource(RecommendedAppsResource, '/explore/apps')