From 65ec14c9d0c9fdf58c2397f4e866c0036782d330 Mon Sep 17 00:00:00 2001 From: waylon <1158341873@qq.com> Date: Wed, 28 Dec 2022 15:03:11 +0800 Subject: [PATCH] =?UTF-8?q?feature:=20=E6=94=AF=E6=8C=81=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E6=94=B6=E8=97=8F=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gcloud/core/admin.py | 5 ++ gcloud/core/apis/drf/serilaziers/project.py | 5 ++ gcloud/core/apis/drf/viewsets/user_project.py | 46 ++++++++++++++++--- .../migrations/0026_userfavoriteproject.py | 26 +++++++++++ gcloud/core/models.py | 23 ++++++++++ gcloud/taskflow3/apis/django/api.py | 2 +- .../core/models/test_user_favorite_project.py | 41 +++++++++++++++++ 7 files changed, 140 insertions(+), 8 deletions(-) create mode 100644 gcloud/core/migrations/0026_userfavoriteproject.py create mode 100644 gcloud/tests/core/models/test_user_favorite_project.py diff --git a/gcloud/core/admin.py b/gcloud/core/admin.py index 2cc580bcab..7a5c87dd9f 100644 --- a/gcloud/core/admin.py +++ b/gcloud/core/admin.py @@ -99,3 +99,8 @@ class EngineConfigAdmin(admin.ModelAdmin): class DisabledComponentAdmin(admin.ModelAdmin): search_fields = ["component_code", "action", "scope"] list_display = ["component_code", "action", "scope"] + + +@admin.register(models.UserFavoriteProject) +class UserFavoriteProjectAdmin(admin.ModelAdmin): + list_display = ["id", "username", "project_id"] diff --git a/gcloud/core/apis/drf/serilaziers/project.py b/gcloud/core/apis/drf/serilaziers/project.py index 710fca1904..933ecfbec0 100644 --- a/gcloud/core/apis/drf/serilaziers/project.py +++ b/gcloud/core/apis/drf/serilaziers/project.py @@ -29,3 +29,8 @@ class Meta: "bk_biz_id", "relate_business", ] + + +class ProjectWithFavSerializer(ProjectSerializer): + is_fav = serializers.BooleanField(read_only=True) + is_user_project = serializers.BooleanField(read_only=True) diff --git a/gcloud/core/apis/drf/viewsets/user_project.py b/gcloud/core/apis/drf/viewsets/user_project.py index dcfa51cc65..a2142667d6 100644 --- a/gcloud/core/apis/drf/viewsets/user_project.py +++ b/gcloud/core/apis/drf/viewsets/user_project.py @@ -10,19 +10,26 @@ an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ +import logging + +from django.db import IntegrityError +from django.db.models import BooleanField, ExpressionWrapper, Q from rest_framework import permissions +from rest_framework.decorators import action from rest_framework.pagination import LimitOffsetPagination +from rest_framework.response import Response -from gcloud.iam_auth import IAMMeta, res_factory -from gcloud.iam_auth.utils import get_user_projects - -from gcloud.core.models import Project from gcloud.core.apis.drf.filtersets import ALL_LOOKUP, AllLookupSupportFilterSet -from gcloud.core.apis.drf.serilaziers import ProjectSerializer from gcloud.core.apis.drf.resource_helpers import ViewSetResourceHelper +from gcloud.core.apis.drf.serilaziers import ProjectWithFavSerializer +from gcloud.core.models import Project, UserFavoriteProject +from gcloud.iam_auth import IAMMeta, res_factory +from gcloud.iam_auth.utils import get_user_projects from .base import GcloudListViewSet +logger = logging.getLogger("root") + class UserProjectFilter(AllLookupSupportFilterSet): class Meta: @@ -39,7 +46,7 @@ class Meta: class UserProjectSetViewSet(GcloudListViewSet): queryset = Project.objects.all().order_by("-id") - serializer_class = ProjectSerializer + serializer_class = ProjectWithFavSerializer permission_classes = [permissions.IsAuthenticated] filterset_class = UserProjectFilter pagination_class = LimitOffsetPagination @@ -56,5 +63,30 @@ class UserProjectSetViewSet(GcloudListViewSet): ) def list(self, request, *args, **kwargs): - self.queryset = get_user_projects(request.user.username) + user_project_ids = list(get_user_projects(request.user.username).values_list("id", flat=True)) + user_fav_project_ids = list(UserFavoriteProject.objects.get_user_favorite_projects(request.user.username)) + self.list_queryset = ( + Project.objects.all() + .annotate( + is_fav=ExpressionWrapper(Q(id__in=user_fav_project_ids), output_field=BooleanField()), + is_user_project=ExpressionWrapper(Q(id__in=user_project_ids), output_field=BooleanField()), + ) + .order_by("-is_fav", "-is_user_project", "id") + ) return super(UserProjectSetViewSet, self).list(request, *args, **kwargs) + + @action(methods=["post"], detail=True) + def favor(self, request, *args, **kwargs): + project_id = kwargs["pk"] + try: + UserFavoriteProject.objects.add_user_favorite_project(request.user.username, project_id) + except IntegrityError as e: + logger.exception(e) + return Response({"result": False, "data": None, "message": "该用户已收藏该项目"}, status=400) + return Response({"result": True, "data": "success", "message": ""}) + + @action(methods=["delete"], detail=True) + def cancel_favor(self, request, *args, **kwargs): + project_id = kwargs["pk"] + UserFavoriteProject.objects.remove_user_favorite_project(request.user.username, project_id) + return Response({"result": True, "data": "success", "message": ""}) diff --git a/gcloud/core/migrations/0026_userfavoriteproject.py b/gcloud/core/migrations/0026_userfavoriteproject.py new file mode 100644 index 0000000000..d448b1c1c2 --- /dev/null +++ b/gcloud/core/migrations/0026_userfavoriteproject.py @@ -0,0 +1,26 @@ +# Generated by Django 3.2.15 on 2023-12-05 06:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("core", "0025_auto_20230609_2101"), + ] + + operations = [ + migrations.CreateModel( + name="UserFavoriteProject", + fields=[ + ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("username", models.CharField(max_length=128, verbose_name="用户名")), + ("project_id", models.IntegerField(verbose_name="项目id")), + ], + options={ + "verbose_name": "用户收藏项目 UserFavoriteProject", + "verbose_name_plural": "用户收藏项目 UserFavoriteProject", + "unique_together": {("username", "project_id")}, + }, + ), + ] diff --git a/gcloud/core/models.py b/gcloud/core/models.py index 660b7ecb6c..76924976f1 100644 --- a/gcloud/core/models.py +++ b/gcloud/core/models.py @@ -314,6 +314,29 @@ def init_user_default_project(self, username, project): return self.create(username=username, default_project=project) +class UserFavoriteProjectManager(models.Manager): + def add_user_favorite_project(self, username, project_id): + return self.create(username=username, project_id=project_id) + + def remove_user_favorite_project(self, username, project_id): + return self.filter(username=username, project_id=project_id).delete() + + def get_user_favorite_projects(self, username): + return self.filter(username=username).values_list("project_id", flat=True) + + +class UserFavoriteProject(models.Model): + username = models.CharField(_("用户名"), max_length=128) + project_id = models.IntegerField(_("项目id")) + + objects = UserFavoriteProjectManager() + + class Meta: + verbose_name = _("用户收藏项目 UserFavoriteProject") + verbose_name_plural = _("用户收藏项目 UserFavoriteProject") + unique_together = ("username", "project_id") + + class UserDefaultProject(models.Model): username = models.CharField(_("用户名"), max_length=255, unique=True) default_project = models.ForeignKey(verbose_name=_("用户默认项目"), to=Project, on_delete=models.CASCADE) diff --git a/gcloud/taskflow3/apis/django/api.py b/gcloud/taskflow3/apis/django/api.py index e1fd809811..b21c27a7b3 100644 --- a/gcloud/taskflow3/apis/django/api.py +++ b/gcloud/taskflow3/apis/django/api.py @@ -205,7 +205,7 @@ def detail(request, project_id): "ex_data": "节点错误信息(string)" } ], - "auto_retry_info": {"node_id": "act1", "auto_retry_times": 3, "max_auto_retry_times": 10}, + "auto_retry_info": "自动重试信息, node_id auto_retry_times max_auto_retry_times 三个 key (dict)", "inputs": "节点输入数据, include_data 为 1 时返回(object or null)", "outputs": "节点输出数据, include_data 为 1 时返回(list)", "ex_data": "节点错误信息, include_data 为 1 时返回(string)" diff --git a/gcloud/tests/core/models/test_user_favorite_project.py b/gcloud/tests/core/models/test_user_favorite_project.py new file mode 100644 index 0000000000..27b9cea03f --- /dev/null +++ b/gcloud/tests/core/models/test_user_favorite_project.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +""" +Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community +Edition) available. +Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at +http://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" + +from django.test import TestCase + +from gcloud.core.models import UserFavoriteProject + + +class UserFavoriteProjectTestCase(TestCase): + def setUp(self): + self.username = "user" + self.project_id = 1 + + def tearDown(self): + UserFavoriteProject.objects.all().delete() + + def test_add_user_favorite_project(self): + self.assertEqual(UserFavoriteProject.objects.count(), 0) + UserFavoriteProject.objects.add_user_favorite_project(self.username, self.project_id) + self.assertEqual(UserFavoriteProject.objects.count(), 1) + + def test_remove_user_favorite_project(self): + UserFavoriteProject.objects.create(username=self.username, project_id=self.project_id) + self.assertEqual(UserFavoriteProject.objects.count(), 1) + UserFavoriteProject.objects.remove_user_favorite_project(self.username, self.project_id) + self.assertEqual(UserFavoriteProject.objects.count(), 0) + + def test_get_user_favorite_projects(self): + UserFavoriteProject.objects.create(username=self.username, project_id=1) + UserFavoriteProject.objects.create(username=self.username, project_id=2) + self.assertEqual(list(UserFavoriteProject.objects.get_user_favorite_projects(self.username)), [1, 2])