views.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. # Copyright: (c) OpenSpug Organization. https://github.com/openspug/spug
  2. # Copyright: (c) <spug.dev@gmail.com>
  3. # Released under the AGPL-3.0 License.
  4. from django.views.generic import View
  5. from django.db.models import F
  6. from libs import json_response, JsonParser, Argument
  7. from apps.app.models import Deploy
  8. from apps.config.models import *
  9. import json
  10. import re
  11. class EnvironmentView(View):
  12. def get(self, request):
  13. query = {}
  14. if not request.user.is_supper:
  15. query['id__in'] = request.user.deploy_perms['envs']
  16. envs = Environment.objects.filter(**query)
  17. return json_response(envs)
  18. def post(self, request):
  19. form, error = JsonParser(
  20. Argument('id', type=int, required=False),
  21. Argument('name', help='请输入环境名称'),
  22. Argument('key', help='请输入唯一标识符'),
  23. Argument('desc', required=False)
  24. ).parse(request.body)
  25. if error is None:
  26. if not re.fullmatch(r'[-\w]+', form.key, re.ASCII):
  27. return json_response(error='标识符必须为字母、数字、-和下划线的组合')
  28. env = Environment.objects.filter(key=form.key).first()
  29. if env and env.id != form.id:
  30. return json_response(error=f'唯一标识符 {form.key} 已存在,请更改后重试')
  31. if form.id:
  32. Environment.objects.filter(pk=form.id).update(**form)
  33. else:
  34. env = Environment.objects.create(created_by=request.user, **form)
  35. env.sort_id = env.id
  36. env.save()
  37. return json_response(error=error)
  38. def patch(self, request):
  39. form, error = JsonParser(
  40. Argument('id', type=int, help='参数错误'),
  41. Argument('sort', filter=lambda x: x in ('up', 'down'), required=False)
  42. ).parse(request.body)
  43. if error is None:
  44. env = Environment.objects.filter(pk=form.id).first()
  45. if not env:
  46. return json_response(error='未找到指定环境')
  47. if form.sort:
  48. if form.sort == 'up':
  49. tmp = Environment.objects.filter(sort_id__gt=env.sort_id).last()
  50. else:
  51. tmp = Environment.objects.filter(sort_id__lt=env.sort_id).first()
  52. if tmp:
  53. tmp.sort_id, env.sort_id = env.sort_id, tmp.sort_id
  54. tmp.save()
  55. env.save()
  56. return json_response(error=error)
  57. def delete(self, request):
  58. form, error = JsonParser(
  59. Argument('id', type=int, help='请指定操作对象')
  60. ).parse(request.GET)
  61. if error is None:
  62. if Config.objects.filter(env_id=form.id).exists():
  63. return json_response(error='该环境已存在关联的配置信息,请删除相关配置后再尝试删除')
  64. if Deploy.objects.filter(env_id=form.id).exists():
  65. return json_response(error='该环境已关联了发布配置,请删除相关发布配置后再尝试删除')
  66. Environment.objects.filter(pk=form.id).delete()
  67. return json_response(error=error)
  68. class ServiceView(View):
  69. def get(self, request):
  70. services = Service.objects.all()
  71. return json_response(services)
  72. def post(self, request):
  73. form, error = JsonParser(
  74. Argument('id', type=int, required=False),
  75. Argument('name', help='请输入服务名称'),
  76. Argument('key', help='请输入唯一标识符'),
  77. Argument('desc', required=False)
  78. ).parse(request.body)
  79. if error is None:
  80. if not re.fullmatch(r'[-\w]+', form.key, re.ASCII):
  81. return json_response(error='标识符必须为字母、数字、-和下划线的组合')
  82. service = Service.objects.filter(key=form.key).first()
  83. if service and service.id != form.id:
  84. return json_response(error=f'唯一标识符 {form.key} 已存在,请更改后重试')
  85. if form.id:
  86. Service.objects.filter(pk=form.id).update(**form)
  87. else:
  88. Service.objects.create(created_by=request.user, **form)
  89. return json_response(error=error)
  90. def delete(self, request):
  91. form, error = JsonParser(
  92. Argument('id', type=int, help='请指定操作对象')
  93. ).parse(request.GET)
  94. if error is None:
  95. if Config.objects.filter(type='src', o_id=form.id).exists():
  96. return json_response(error='该服务已存在关联的配置信息,请删除相关配置后再尝试删除')
  97. Service.objects.filter(pk=form.id).delete()
  98. return json_response(error=error)
  99. class ConfigView(View):
  100. def get(self, request):
  101. form, error = JsonParser(
  102. Argument('id', type=int, help='未指定操作对象'),
  103. Argument('type', filter=lambda x: x in dict(Config.TYPES), help='缺少必要参数'),
  104. Argument('env_id', type=int, help='缺少必要参数'),
  105. ).parse(request.GET)
  106. if error is None:
  107. form.o_id, data = form.pop('id'), []
  108. for item in Config.objects.filter(**form).annotate(update_user=F('updated_by__nickname')):
  109. tmp = item.to_dict()
  110. tmp['update_user'] = item.update_user
  111. data.append(tmp)
  112. return json_response(data)
  113. return json_response(error=error)
  114. def post(self, request):
  115. form, error = JsonParser(
  116. Argument('o_id', type=int, help='缺少必要参数'),
  117. Argument('type', filter=lambda x: x in dict(Config.TYPES), help='缺少必要参数'),
  118. Argument('envs', type=list, filter=lambda x: len(x), help='请选择环境'),
  119. Argument('key', help='请输入Key'),
  120. Argument('is_public', type=bool, help='缺少必要参数'),
  121. Argument('value', type=str, default=''),
  122. Argument('desc', required=False)
  123. ).parse(request.body)
  124. if error is None:
  125. form.value = form.value.strip()
  126. form.updated_at = human_datetime()
  127. form.updated_by = request.user
  128. envs = form.pop('envs')
  129. for env_id in envs:
  130. cf = Config.objects.filter(o_id=form.o_id, type=form.type, env_id=env_id, key=form.key).first()
  131. if cf:
  132. raise Exception(f'{cf.env.name} 中已存在该Key')
  133. Config.objects.create(env_id=env_id, **form)
  134. ConfigHistory.objects.create(action='1', env_id=env_id, **form)
  135. return json_response(error=error)
  136. def patch(self, request):
  137. form, error = JsonParser(
  138. Argument('id', type=int, help='缺少必要参数'),
  139. Argument('value', type=str, default=''),
  140. Argument('is_public', type=bool, help='缺少必要参数'),
  141. Argument('desc', required=False)
  142. ).parse(request.body)
  143. if error is None:
  144. form.value = form.value.strip()
  145. config = Config.objects.filter(pk=form.id).first()
  146. if not config:
  147. return json_response(error='未找到指定对象')
  148. config.desc = form.desc
  149. config.is_public = form.is_public
  150. if config.value != form.value:
  151. old_value = config.value
  152. config.value = form.value
  153. config.updated_at = human_datetime()
  154. config.updated_by = request.user
  155. ConfigHistory.objects.create(
  156. action='2',
  157. old_value=old_value,
  158. **config.to_dict(excludes=('id',)))
  159. config.save()
  160. return json_response(error=error)
  161. def delete(self, request):
  162. form, error = JsonParser(
  163. Argument('id', type=int, help='未指定操作对象')
  164. ).parse(request.GET)
  165. if error is None:
  166. config = Config.objects.filter(pk=form.id).first()
  167. if config:
  168. ConfigHistory.objects.create(
  169. action='3',
  170. old_value=config.value,
  171. value='',
  172. updated_at=human_datetime(),
  173. updated_by=request.user,
  174. **config.to_dict(excludes=('id', 'value', 'updated_at', 'updated_by_id'))
  175. )
  176. config.delete()
  177. return json_response(error=error)
  178. class HistoryView(View):
  179. def post(self, request):
  180. form, error = JsonParser(
  181. Argument('o_id', type=int, help='缺少必要参数'),
  182. Argument('env_id', type=int, help='缺少必要参数'),
  183. Argument('type', filter=lambda x: x in dict(Config.TYPES), help='缺少必要参数')
  184. ).parse(request.body)
  185. if error is None:
  186. data = []
  187. for item in ConfigHistory.objects.filter(**form).annotate(update_user=F('updated_by__nickname')):
  188. tmp = item.to_dict()
  189. tmp['action_alias'] = item.get_action_display()
  190. tmp['update_user'] = item.update_user
  191. data.append(tmp)
  192. return json_response(data)
  193. return json_response(error=error)
  194. def post_diff(request):
  195. form, error = JsonParser(
  196. Argument('o_id', type=int, help='缺少必要参数'),
  197. Argument('type', filter=lambda x: x in dict(Config.TYPES), help='缺少必要参数'),
  198. Argument('envs', type=list, filter=lambda x: len(x), help='缺少必要参数'),
  199. ).parse(request.body)
  200. if error is None:
  201. data, form.env_id__in = {}, form.pop('envs')
  202. for item in Config.objects.filter(**form).order_by('key'):
  203. if item.key in data:
  204. data[item.key][item.env_id] = item.value
  205. else:
  206. data[item.key] = {'key': item.key, item.env_id: item.value}
  207. return json_response(list(data.values()))
  208. return json_response(error=error)
  209. def parse_json(request):
  210. form, error = JsonParser(
  211. Argument('o_id', type=int, help='缺少必要参数'),
  212. Argument('type', filter=lambda x: x in dict(Config.TYPES), help='缺少必要参数'),
  213. Argument('env_id', type=int, help='缺少必要参数'),
  214. Argument('data', type=dict, help='缺少必要参数')
  215. ).parse(request.body)
  216. if error is None:
  217. data = form.pop('data')
  218. _parse(request, form, data)
  219. return json_response(error=error)
  220. def parse_text(request):
  221. form, error = JsonParser(
  222. Argument('o_id', type=int, help='缺少必要参数'),
  223. Argument('type', filter=lambda x: x in dict(Config.TYPES), help='缺少必要参数'),
  224. Argument('env_id', type=int, help='缺少必要参数'),
  225. Argument('data', handler=str.strip, help='缺少必要参数')
  226. ).parse(request.body)
  227. if error is None:
  228. data = {}
  229. for line in form.pop('data').split('\n'):
  230. line = line.strip()
  231. if not line or line[0] in ('#', ';'):
  232. continue
  233. fields = line.split('=', 1)
  234. if len(fields) != 2 or fields[0].strip() == '':
  235. return json_response(error=f'解析配置{line!r}失败,确认其遵循 key = value 格式')
  236. data[fields[0].strip()] = fields[1].strip()
  237. _parse(request, form, data)
  238. return json_response(error=error)
  239. def _parse(request, query, data):
  240. for item in Config.objects.filter(**query):
  241. if item.key in data:
  242. value = _filter_value(data.pop(item.key))
  243. if item.value != value:
  244. old_value = item.value
  245. item.value = value
  246. item.updated_at = human_datetime()
  247. item.updated_by = request.user
  248. item.save()
  249. ConfigHistory.objects.create(
  250. action='2',
  251. old_value=old_value,
  252. **item.to_dict(excludes=('id',)))
  253. else:
  254. ConfigHistory.objects.create(
  255. action='3',
  256. old_value=item.value,
  257. value='',
  258. updated_at=human_datetime(),
  259. updated_by=request.user,
  260. **item.to_dict(excludes=('id', 'value', 'updated_at', 'updated_by_id'))
  261. )
  262. item.delete()
  263. for key, value in data.items():
  264. query.key = key
  265. query.is_public = False
  266. query.value = _filter_value(value)
  267. query.updated_at = human_datetime()
  268. query.updated_by = request.user
  269. Config.objects.create(**query)
  270. ConfigHistory.objects.create(action='1', **query)
  271. def _filter_value(value):
  272. if isinstance(value, (str, int)):
  273. value = str(value).strip()
  274. else:
  275. value = json.dumps(value)
  276. return value