├── LICENSE ├── README.md ├── backend ├── .gitignore ├── README.md ├── accounts │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── permissions.py │ ├── serializers.py │ ├── tests.py │ ├── urls.py │ ├── utils.py │ └── views.py ├── manage.py ├── pyproject.toml ├── questions │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ ├── 0001_initial.py │ │ └── __init__.py │ ├── models.py │ ├── serializers.py │ ├── tests.py │ ├── urls.py │ └── views.py ├── requirements.txt └── src │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── frontend ├── .gitignore ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── public └── favicon.ico ├── src ├── App.vue ├── components │ ├── accounts │ │ ├── Login.vue │ │ ├── Profile.vue │ │ └── Register.vue │ └── questions │ │ ├── Categories.vue │ │ ├── CreateQuestion.vue │ │ ├── ProfileAnswers.vue │ │ ├── ProfileAnswersEdit.vue │ │ ├── ProfileQuestions.vue │ │ ├── ProfileQuestionsEdit.vue │ │ ├── Question.vue │ │ ├── Questions.vue │ │ ├── QuestionsByTag.vue │ │ ├── QuestionsOpen.vue │ │ └── QuestionsSolved.vue ├── main.js ├── router │ └── index.js ├── store │ └── index.js └── views │ └── Home.vue └── vite.config.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 sinisaos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Example of single page application made with [Django Rest Framework](https://www.django-rest-framework.org/) and [Vue JS](https://vuejs.org/). 2 | 3 | For backend installation look at backend readme. 4 | 5 | For frontend installation look at frontend readme. 6 | -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.pot 3 | *.pyc 4 | __pycache__/ 5 | db.sqlite3 6 | .vscode 7 | .ruff_cache -------------------------------------------------------------------------------- /backend/README.md: -------------------------------------------------------------------------------- 1 | Open terminal and run: 2 | 3 | ```shell 4 | virtualenv -p python3 envname 5 | cd envname 6 | source bin/activate 7 | git clone https://github.com/sinisaos/drf-vue.git 8 | cd drf-vue/backend/ 9 | pip install -r requirements.txt 10 | python manage.py migrate 11 | python manage.py createsuperuser 12 | python manage.py runserver 13 | ``` 14 | 15 | 16 | -------------------------------------------------------------------------------- /backend/accounts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinisaos/drf-vue/7c879b5983e32a49b0952247a5fb79747b9bdf09/backend/accounts/__init__.py -------------------------------------------------------------------------------- /backend/accounts/admin.py: -------------------------------------------------------------------------------- 1 | 2 | # Register your models here. 3 | -------------------------------------------------------------------------------- /backend/accounts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountsConfig(AppConfig): 5 | name = "accounts" 6 | -------------------------------------------------------------------------------- /backend/accounts/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinisaos/drf-vue/7c879b5983e32a49b0952247a5fb79747b9bdf09/backend/accounts/migrations/__init__.py -------------------------------------------------------------------------------- /backend/accounts/models.py: -------------------------------------------------------------------------------- 1 | 2 | # Create your models here. 3 | -------------------------------------------------------------------------------- /backend/accounts/permissions.py: -------------------------------------------------------------------------------- 1 | from rest_framework.permissions import SAFE_METHODS, BasePermission 2 | 3 | 4 | class IsOwnerOrAdmin(BasePermission): 5 | def has_object_permission(self, request, view, obj): 6 | if request.method in SAFE_METHODS: 7 | return True 8 | return obj.pk == request.user.pk or request.user.is_staff 9 | -------------------------------------------------------------------------------- /backend/accounts/serializers.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import get_user_model, password_validation 2 | from django.contrib.auth.models import BaseUserManager 3 | from rest_framework import serializers 4 | from rest_framework.authtoken.models import Token 5 | 6 | User = get_user_model() 7 | 8 | 9 | class UserSerializer(serializers.ModelSerializer): 10 | 11 | class Meta: 12 | model = User 13 | fields = ["id", "username", "email", "date_joined", "last_login", "auth_token"] 14 | 15 | 16 | class UserLoginSerializer(serializers.Serializer): 17 | username = serializers.CharField(max_length=300, required=True) 18 | password = serializers.CharField(required=True, write_only=True) 19 | 20 | 21 | class EmptySerializer(serializers.Serializer): 22 | pass 23 | 24 | 25 | class UserRegisterSerializer(serializers.ModelSerializer): 26 | """ 27 | A user serializer for registering the user 28 | """ 29 | 30 | auth_token = serializers.SerializerMethodField() 31 | 32 | class Meta: 33 | model = User 34 | fields = [ 35 | "id", 36 | "username", 37 | "email", 38 | "password", 39 | "auth_token", 40 | "date_joined", 41 | "last_login", 42 | ] 43 | 44 | def get_auth_token(self, obj): 45 | token = Token.objects.create(user=obj) 46 | return token.key 47 | 48 | def validate_email(self, value): 49 | user = User.objects.filter(email=value) 50 | if user: 51 | raise serializers.ValidationError("A user with that email already exists.") 52 | return BaseUserManager.normalize_email(value) 53 | 54 | def validate_password(self, value): 55 | password_validation.validate_password(value) 56 | return value 57 | -------------------------------------------------------------------------------- /backend/accounts/tests.py: -------------------------------------------------------------------------------- 1 | 2 | # Create your tests here. 3 | -------------------------------------------------------------------------------- /backend/accounts/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from rest_framework import routers 3 | 4 | from accounts.views import ( 5 | AnswerDetail, 6 | AnswerList, 7 | AuthViewSet, 8 | QuestionDetail, 9 | QuestionList, 10 | UserViewSet, 11 | ) 12 | 13 | router = routers.DefaultRouter(trailing_slash=False) 14 | router.register("api/auth", AuthViewSet, basename="auth") 15 | router.register("api/users", UserViewSet, basename="users") 16 | 17 | urlpatterns = router.urls 18 | 19 | urlpatterns += [ 20 | path("api/users//questions", QuestionList.as_view()), 21 | path( 22 | "api/users//questions/", QuestionDetail.as_view() 23 | ), 24 | path("api/users//answers", AnswerList.as_view()), 25 | path("api/users//answers/", AnswerDetail.as_view()), 26 | ] 27 | -------------------------------------------------------------------------------- /backend/accounts/utils.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import authenticate, get_user_model 2 | from rest_framework import serializers 3 | 4 | 5 | def get_and_authenticate_user(username, password): 6 | user = authenticate(username=username, password=password) 7 | if user is None: 8 | raise serializers.ValidationError( 9 | "Invalid username/password. Please try again!" 10 | ) 11 | return user 12 | 13 | 14 | def create_user_account(email, password, **extra_fields): 15 | user = get_user_model().objects.create_user( 16 | email=email, password=password, **extra_fields 17 | ) 18 | return user 19 | -------------------------------------------------------------------------------- /backend/accounts/views.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | from django.contrib.auth import get_user_model, logout 4 | from django.core.exceptions import ImproperlyConfigured 5 | from rest_framework import generics, status, viewsets 6 | from rest_framework.authtoken.models import Token 7 | from rest_framework.decorators import action 8 | from rest_framework.pagination import PageNumberPagination 9 | from rest_framework.permissions import AllowAny, IsAuthenticated 10 | from rest_framework.response import Response 11 | 12 | from questions.models import Answer, Question 13 | from questions.serializers import AnswerSerializer, QuestionSerializer 14 | 15 | from . import serializers 16 | from .permissions import IsOwnerOrAdmin 17 | from .utils import create_user_account, get_and_authenticate_user 18 | 19 | User = get_user_model() 20 | 21 | 22 | class AuthViewSet(viewsets.GenericViewSet): 23 | permission_classes = [AllowAny] 24 | serializer_class = serializers.EmptySerializer 25 | serializer_classes = { 26 | "login": serializers.UserLoginSerializer, 27 | "register": serializers.UserRegisterSerializer, 28 | } 29 | 30 | @action(methods=["POST"], detail=False) 31 | def login(self, request): 32 | serializer = self.get_serializer(data=request.data) 33 | serializer.is_valid(raise_exception=True) 34 | user = get_and_authenticate_user(**serializer.validated_data) 35 | data = serializers.UserSerializer(user).data 36 | data["last_login"] = datetime.datetime.now() 37 | return Response(data=data, status=status.HTTP_200_OK) 38 | 39 | @action(methods=["POST"], detail=False) 40 | def register(self, request): 41 | serializer = self.get_serializer(data=request.data) 42 | serializer.is_valid(raise_exception=True) 43 | user = create_user_account(**serializer.validated_data) 44 | data = serializers.UserRegisterSerializer(user).data 45 | data["last_login"] = datetime.datetime.now() 46 | # create token for new user 47 | token, _ = Token.objects.get_or_create(user=user) 48 | data["auth_token"] = token.key 49 | return Response(data=data, status=status.HTTP_201_CREATED) 50 | 51 | @action(methods=["POST"], detail=False) 52 | def logout(self, request): 53 | logout(request) 54 | data = {"success": "Sucessfully logged out"} 55 | return Response(data=data, status=status.HTTP_200_OK) 56 | 57 | def get_serializer_class(self): 58 | if not isinstance(self.serializer_classes, dict): 59 | raise ImproperlyConfigured("serializer_classes should be a dict mapping.") 60 | if self.action in self.serializer_classes.keys(): 61 | return self.serializer_classes[self.action] 62 | return super().get_serializer_class() 63 | 64 | 65 | class UserViewSet(viewsets.ModelViewSet): 66 | permission_classes = [IsAuthenticated, IsOwnerOrAdmin] 67 | queryset = User.objects.prefetch_related("auth_token") 68 | serializer_class = serializers.UserSerializer 69 | 70 | 71 | class QuestionList(generics.ListAPIView): 72 | permission_classes = [IsAuthenticated] 73 | serializer_class = QuestionSerializer 74 | pagination_class = PageNumberPagination 75 | 76 | def get_queryset(self): 77 | return Question.objects.filter(user_id=self.kwargs["user_id"]) 78 | 79 | 80 | class AnswerList(generics.ListAPIView): 81 | permission_classes = [IsAuthenticated] 82 | serializer_class = AnswerSerializer 83 | pagination_class = PageNumberPagination 84 | 85 | def get_queryset(self): 86 | return Answer.objects.filter(user_id=self.kwargs["user_id"]) 87 | 88 | 89 | class QuestionDetail(generics.RetrieveUpdateDestroyAPIView): 90 | permission_classes = [IsAuthenticated] 91 | serializer_class = QuestionSerializer 92 | lookup_url_kwarg = "question_id" 93 | 94 | def get_queryset(self): 95 | return Question.objects.filter(user_id=self.kwargs["user_id"]) 96 | 97 | 98 | class AnswerDetail(generics.RetrieveUpdateDestroyAPIView): 99 | permission_classes = [IsAuthenticated] 100 | serializer_class = AnswerSerializer 101 | lookup_url_kwarg = "answer_id" 102 | 103 | def get_queryset(self): 104 | return Answer.objects.filter(user_id=self.kwargs["user_id"]) 105 | -------------------------------------------------------------------------------- /backend/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "src.settings") 9 | try: 10 | from django.core.management import execute_from_command_line 11 | except ImportError as exc: 12 | raise ImportError( 13 | "Couldn't import Django. Are you sure it's installed and " 14 | "available on your PYTHONPATH environment variable? Did you " 15 | "forget to activate a virtual environment?" 16 | ) from exc 17 | execute_from_command_line(sys.argv) 18 | 19 | 20 | if __name__ == "__main__": 21 | main() 22 | -------------------------------------------------------------------------------- /backend/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.ruff] 2 | line-length = 88 3 | lint.select = ["F", "E", "W", "I"] 4 | 5 | [tool.black] 6 | line-length = 88 -------------------------------------------------------------------------------- /backend/questions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinisaos/drf-vue/7c879b5983e32a49b0952247a5fb79747b9bdf09/backend/questions/__init__.py -------------------------------------------------------------------------------- /backend/questions/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .models import Answer, Question 4 | 5 | 6 | class QuestionAdmin(admin.ModelAdmin): 7 | list_display = ("title", "created", "updated", "views", "likes") 8 | 9 | 10 | admin.site.register(Question, QuestionAdmin) 11 | admin.site.register(Answer) 12 | -------------------------------------------------------------------------------- /backend/questions/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class QuestionsConfig(AppConfig): 5 | name = "questions" 6 | -------------------------------------------------------------------------------- /backend/questions/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.6 on 2020-05-08 04:25 2 | 3 | import django.db.models.deletion 4 | import taggit.managers 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | ("taggit", "0003_taggeditem_add_unique_index"), 15 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 16 | ] 17 | 18 | operations = [ 19 | migrations.CreateModel( 20 | name="Question", 21 | fields=[ 22 | ( 23 | "id", 24 | models.AutoField( 25 | auto_created=True, 26 | primary_key=True, 27 | serialize=False, 28 | verbose_name="ID", 29 | ), 30 | ), 31 | ("title", models.CharField(max_length=256, verbose_name="question")), 32 | ("content", models.TextField()), 33 | ( 34 | "slug", 35 | models.SlugField( 36 | default="djangodbmodelsfieldscharfield", unique=True 37 | ), 38 | ), 39 | ("created", models.DateTimeField(auto_now_add=True)), 40 | ("updated", models.DateTimeField(auto_now=True)), 41 | ("likes", models.PositiveIntegerField(default=0)), 42 | ("views", models.PositiveIntegerField(default=0)), 43 | ( 44 | "tags", 45 | taggit.managers.TaggableManager( 46 | help_text="A comma-separated list of tags.", 47 | through="taggit.TaggedItem", 48 | to="taggit.Tag", 49 | verbose_name="Tags", 50 | ), 51 | ), 52 | ( 53 | "user", 54 | models.ForeignKey( 55 | on_delete=django.db.models.deletion.CASCADE, 56 | to=settings.AUTH_USER_MODEL, 57 | ), 58 | ), 59 | ], 60 | options={ 61 | "ordering": ["-created"], 62 | }, 63 | ), 64 | migrations.CreateModel( 65 | name="Answer", 66 | fields=[ 67 | ( 68 | "id", 69 | models.AutoField( 70 | auto_created=True, 71 | primary_key=True, 72 | serialize=False, 73 | verbose_name="ID", 74 | ), 75 | ), 76 | ("content", models.TextField()), 77 | ("likes", models.PositiveIntegerField(default=0)), 78 | ("created", models.DateTimeField(auto_now_add=True)), 79 | ("updated", models.DateTimeField(auto_now=True)), 80 | ("is_accepted", models.BooleanField(default=False)), 81 | ( 82 | "question", 83 | models.ForeignKey( 84 | on_delete=django.db.models.deletion.CASCADE, 85 | related_name="answers", 86 | to="questions.Question", 87 | ), 88 | ), 89 | ( 90 | "user", 91 | models.ForeignKey( 92 | on_delete=django.db.models.deletion.CASCADE, 93 | to=settings.AUTH_USER_MODEL, 94 | ), 95 | ), 96 | ], 97 | options={ 98 | "ordering": ["-created"], 99 | }, 100 | ), 101 | ] 102 | -------------------------------------------------------------------------------- /backend/questions/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinisaos/drf-vue/7c879b5983e32a49b0952247a5fb79747b9bdf09/backend/questions/migrations/__init__.py -------------------------------------------------------------------------------- /backend/questions/models.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import get_user_model 2 | from django.db import models 3 | from django.utils.text import slugify 4 | from taggit.managers import TaggableManager 5 | 6 | User = get_user_model() 7 | 8 | 9 | class Question(models.Model): 10 | user = models.ForeignKey(User, on_delete=models.CASCADE) 11 | title = models.CharField(max_length=256, verbose_name="question") 12 | content = models.TextField() 13 | slug = models.SlugField(default=slugify(title), unique=True) 14 | created = models.DateTimeField(auto_now_add=True) 15 | updated = models.DateTimeField(auto_now=True) 16 | likes = models.PositiveIntegerField(default=0) 17 | views = models.PositiveIntegerField(default=0) 18 | tags = TaggableManager() 19 | 20 | def __str__(self): 21 | return self.title 22 | 23 | class Meta: 24 | ordering = ["-created"] 25 | 26 | def save(self, *args, **kwargs): 27 | self.slug = slugify(self.title) 28 | super(Question, self).save(*args, **kwargs) 29 | 30 | def get_answer_count(self): 31 | return Question.objects.filter(answers__question=self).count() 32 | 33 | def get_accepted_answer(self): 34 | try: 35 | accepted_answer = Answer.objects.get(question=self, is_accepted=True) 36 | return accepted_answer 37 | except Answer.DoesNotExist: 38 | accepted_answer = None 39 | 40 | 41 | class Answer(models.Model): 42 | user = models.ForeignKey(User, on_delete=models.CASCADE) 43 | question = models.ForeignKey( 44 | Question, related_name="answers", on_delete=models.CASCADE 45 | ) 46 | content = models.TextField() 47 | likes = models.PositiveIntegerField(default=0) 48 | created = models.DateTimeField(auto_now_add=True) 49 | updated = models.DateTimeField(auto_now=True) 50 | is_accepted = models.BooleanField(default=False) 51 | 52 | class Meta: 53 | ordering = ["-created"] 54 | -------------------------------------------------------------------------------- /backend/questions/serializers.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth import get_user_model 2 | from rest_framework import serializers 3 | from taggit.models import Tag 4 | from taggit.serializers import TaggitSerializer, TagListSerializerField 5 | 6 | from .models import Answer, Question 7 | 8 | User = get_user_model() 9 | 10 | 11 | class AnswerSerializer(serializers.ModelSerializer): 12 | answer_author = serializers.ReadOnlyField(source="user.username") 13 | user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all()) 14 | question = serializers.PrimaryKeyRelatedField(queryset=Question.objects.all()) 15 | 16 | class Meta: 17 | model = Answer 18 | fields = "__all__" 19 | 20 | 21 | class QuestionSerializer(TaggitSerializer, serializers.ModelSerializer): 22 | question_author = serializers.ReadOnlyField(source="user.username") 23 | get_answer_count = serializers.IntegerField(read_only=True) 24 | get_accepted_answer = serializers.BooleanField(read_only=True) 25 | answers = AnswerSerializer(many=True, read_only=True) 26 | user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all()) 27 | tags = TagListSerializerField() 28 | 29 | class Meta: 30 | model = Question 31 | fields = "__all__" 32 | 33 | 34 | class TagSerializer(serializers.ModelSerializer): 35 | count_tags = serializers.IntegerField() 36 | 37 | class Meta: 38 | model = Tag 39 | fields = "__all__" 40 | -------------------------------------------------------------------------------- /backend/questions/tests.py: -------------------------------------------------------------------------------- 1 | 2 | # Create your tests here. 3 | -------------------------------------------------------------------------------- /backend/questions/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from rest_framework import routers 3 | 4 | from .views import ( 5 | AnswerViewSet, 6 | CategoryListView, 7 | OpenQuestionListView, 8 | QuestionViewSet, 9 | SolvedQuestionListView, 10 | TagListView, 11 | ) 12 | 13 | router = routers.DefaultRouter(trailing_slash=False) 14 | router.register("questions", QuestionViewSet, basename="questions") 15 | router.register("answers", AnswerViewSet, basename="answers") 16 | 17 | 18 | urlpatterns = router.urls 19 | 20 | urlpatterns += [ 21 | path("solved", SolvedQuestionListView.as_view()), 22 | path("open", OpenQuestionListView.as_view()), 23 | path("tags/", TagListView.as_view()), 24 | path("categories", CategoryListView.as_view()), 25 | ] 26 | -------------------------------------------------------------------------------- /backend/questions/views.py: -------------------------------------------------------------------------------- 1 | from django.db.models import Count 2 | from rest_framework import filters, generics, viewsets 3 | from rest_framework.pagination import PageNumberPagination 4 | from taggit.models import Tag 5 | 6 | from .models import Answer, Question 7 | from .serializers import AnswerSerializer, QuestionSerializer, TagSerializer 8 | 9 | 10 | class QuestionViewSet(viewsets.ModelViewSet): 11 | filter_backends = [filters.SearchFilter, filters.OrderingFilter] 12 | search_fields = ["title", "content"] 13 | ordering_fields = ["id", "likes", "views"] 14 | queryset = Question.objects.all() 15 | serializer_class = QuestionSerializer 16 | 17 | def retrieve(self, request, *args, **kwargs): 18 | question = self.get_object() 19 | question.views += 1 20 | question.save(update_fields=("views",)) 21 | return super().retrieve(request, *args, **kwargs) 22 | 23 | 24 | class AnswerViewSet(viewsets.ModelViewSet): 25 | queryset = Answer.objects.all() 26 | serializer_class = AnswerSerializer 27 | 28 | 29 | class OpenQuestionListView(generics.ListAPIView): 30 | filter_backends = [filters.SearchFilter, filters.OrderingFilter] 31 | search_fields = ["title", "content"] 32 | ordering_fields = ["id", "likes", "views"] 33 | pagination_class = PageNumberPagination 34 | serializer_class = QuestionSerializer 35 | 36 | def get_queryset(self): 37 | queryset = Question.objects.select_related("user").prefetch_related( 38 | "answers", "tags" 39 | ) 40 | queryset_ids = [obj.id for obj in queryset if not obj.get_accepted_answer()] 41 | queryset = queryset.filter(id__in=queryset_ids) 42 | return queryset 43 | 44 | 45 | class SolvedQuestionListView(generics.ListAPIView): 46 | filter_backends = [filters.SearchFilter, filters.OrderingFilter] 47 | search_fields = ["title", "content"] 48 | ordering_fields = ["id", "likes", "views"] 49 | serializer_class = QuestionSerializer 50 | pagination_class = PageNumberPagination 51 | 52 | def get_queryset(self): 53 | queryset = Question.objects.select_related("user").prefetch_related( 54 | "answers", "tags" 55 | ) 56 | queryset_ids = [obj.id for obj in queryset if obj.get_accepted_answer()] 57 | queryset = queryset.filter(id__in=queryset_ids) 58 | return queryset 59 | 60 | 61 | class TagListView(generics.ListAPIView): 62 | serializer_class = QuestionSerializer 63 | 64 | def get_queryset(self): 65 | return Question.objects.filter(tags__slug=self.kwargs.get("slug")).all() 66 | 67 | 68 | class CategoryListView(generics.ListAPIView): 69 | serializer_class = TagSerializer 70 | pagination_class = None 71 | 72 | def get_queryset(self): 73 | return Tag.objects.all().annotate(count_tags=Count("taggit_taggeditem_items")) 74 | -------------------------------------------------------------------------------- /backend/requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref 2 | Django 3 | djangorestframework 4 | django-cors-headers 5 | django-taggit 6 | pytz 7 | ruff 8 | sqlparse 9 | -------------------------------------------------------------------------------- /backend/src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinisaos/drf-vue/7c879b5983e32a49b0952247a5fb79747b9bdf09/backend/src/__init__.py -------------------------------------------------------------------------------- /backend/src/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for src project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "src.settings") 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /backend/src/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for src project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.0.6. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.0/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.0/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = "i@shh($sp-3i40*$^k7fo!6=m54)xorkbwtn3w0$#hox3b!ph*" 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | "django.contrib.admin", 35 | "django.contrib.auth", 36 | "django.contrib.contenttypes", 37 | "django.contrib.sessions", 38 | "django.contrib.messages", 39 | "django.contrib.staticfiles", 40 | "rest_framework", 41 | "rest_framework.authtoken", 42 | "corsheaders", 43 | "taggit", 44 | "accounts", 45 | "questions", 46 | ] 47 | 48 | REST_FRAMEWORK = { 49 | "DEFAULT_AUTHENTICATION_CLASSES": [ 50 | "rest_framework.authentication.TokenAuthentication", 51 | ], 52 | "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination", 53 | "PAGE_SIZE": 3, 54 | } 55 | 56 | MIDDLEWARE = [ 57 | "django.middleware.security.SecurityMiddleware", 58 | "django.contrib.sessions.middleware.SessionMiddleware", 59 | "corsheaders.middleware.CorsMiddleware", 60 | "django.middleware.common.CommonMiddleware", 61 | "django.middleware.csrf.CsrfViewMiddleware", 62 | "django.contrib.auth.middleware.AuthenticationMiddleware", 63 | "django.contrib.messages.middleware.MessageMiddleware", 64 | "django.middleware.clickjacking.XFrameOptionsMiddleware", 65 | ] 66 | 67 | ROOT_URLCONF = "src.urls" 68 | 69 | TEMPLATES = [ 70 | { 71 | "BACKEND": "django.template.backends.django.DjangoTemplates", 72 | "DIRS": [], 73 | "APP_DIRS": True, 74 | "OPTIONS": { 75 | "context_processors": [ 76 | "django.template.context_processors.debug", 77 | "django.template.context_processors.request", 78 | "django.contrib.auth.context_processors.auth", 79 | "django.contrib.messages.context_processors.messages", 80 | ], 81 | }, 82 | }, 83 | ] 84 | 85 | WSGI_APPLICATION = "src.wsgi.application" 86 | 87 | 88 | # Database 89 | # https://docs.djangoproject.com/en/3.0/ref/settings/#databases 90 | 91 | DATABASES = { 92 | "default": { 93 | "ENGINE": "django.db.backends.sqlite3", 94 | "NAME": os.path.join(BASE_DIR, "db.sqlite3"), 95 | } 96 | } 97 | 98 | 99 | # Password validation 100 | # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators 101 | 102 | AUTH_PASSWORD_VALIDATORS = [ 103 | { 104 | "NAME": ( 105 | "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" 106 | ), 107 | }, 108 | { 109 | "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", 110 | }, 111 | { 112 | "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", 113 | }, 114 | { 115 | "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", 116 | }, 117 | ] 118 | 119 | 120 | # Internationalization 121 | # https://docs.djangoproject.com/en/3.0/topics/i18n/ 122 | 123 | LANGUAGE_CODE = "en-us" 124 | 125 | TIME_ZONE = "Europe/Zagreb" 126 | 127 | USE_I18N = True 128 | 129 | USE_L10N = True 130 | 131 | USE_TZ = True 132 | 133 | 134 | # Static files (CSS, JavaScript, Images) 135 | # https://docs.djangoproject.com/en/3.0/howto/static-files/ 136 | 137 | STATIC_URL = "/static/" 138 | 139 | CORS_ORIGIN_WHITELIST = ["http://localhost:5173"] 140 | 141 | CORS_ALLOW_CREDENTIALS = True 142 | 143 | DEFAULT_AUTO_FIELD = "django.db.models.AutoField" 144 | -------------------------------------------------------------------------------- /backend/src/urls.py: -------------------------------------------------------------------------------- 1 | """src URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.0/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | 17 | from django.contrib import admin 18 | from django.urls import include, path 19 | 20 | urlpatterns = [ 21 | path("", include("accounts.urls")), 22 | path("api/", include("questions.urls")), 23 | path("admin/", admin.site.urls), 24 | ] 25 | -------------------------------------------------------------------------------- /backend/src/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for src project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "src.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | node_modules 13 | dist-ssr 14 | *.local 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # frontend 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run dev 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` -------------------------------------------------------------------------------- /frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | VueDRF 11 | 12 | 13 | 14 |
15 |
16 | 17 |
18 |
19 |
20 |

© VueDRF 2020

21 |
22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /frontend/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "frontend", 9 | "version": "0.0.0", 10 | "dependencies": { 11 | "@vuelidate/core": "^2.0.3", 12 | "@vuelidate/validators": "^2.0.4", 13 | "axios": "^1.7.7", 14 | "bootstrap": "^5.3.3", 15 | "bootstrap-vue-next": "^0.25.10", 16 | "dayjs": "^1.11.13", 17 | "vue": "^3.5.12", 18 | "vue-router": "^4.4.5", 19 | "vuex": "^4.0.2", 20 | "vuex-persist": "^3.1.3" 21 | }, 22 | "devDependencies": { 23 | "@vitejs/plugin-vue": "^5.1.4", 24 | "unplugin-vue-components": "^0.27.4", 25 | "vite": "^5.4.14" 26 | } 27 | }, 28 | "node_modules/@antfu/utils": { 29 | "version": "0.7.10", 30 | "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz", 31 | "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", 32 | "dev": true, 33 | "license": "MIT", 34 | "funding": { 35 | "url": "https://github.com/sponsors/antfu" 36 | } 37 | }, 38 | "node_modules/@babel/helper-string-parser": { 39 | "version": "7.25.9", 40 | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", 41 | "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", 42 | "license": "MIT", 43 | "engines": { 44 | "node": ">=6.9.0" 45 | } 46 | }, 47 | "node_modules/@babel/helper-validator-identifier": { 48 | "version": "7.25.9", 49 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", 50 | "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", 51 | "license": "MIT", 52 | "engines": { 53 | "node": ">=6.9.0" 54 | } 55 | }, 56 | "node_modules/@babel/parser": { 57 | "version": "7.26.1", 58 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.1.tgz", 59 | "integrity": "sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==", 60 | "license": "MIT", 61 | "dependencies": { 62 | "@babel/types": "^7.26.0" 63 | }, 64 | "bin": { 65 | "parser": "bin/babel-parser.js" 66 | }, 67 | "engines": { 68 | "node": ">=6.0.0" 69 | } 70 | }, 71 | "node_modules/@babel/types": { 72 | "version": "7.26.0", 73 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", 74 | "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", 75 | "license": "MIT", 76 | "dependencies": { 77 | "@babel/helper-string-parser": "^7.25.9", 78 | "@babel/helper-validator-identifier": "^7.25.9" 79 | }, 80 | "engines": { 81 | "node": ">=6.9.0" 82 | } 83 | }, 84 | "node_modules/@esbuild/aix-ppc64": { 85 | "version": "0.21.5", 86 | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", 87 | "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", 88 | "cpu": [ 89 | "ppc64" 90 | ], 91 | "dev": true, 92 | "license": "MIT", 93 | "optional": true, 94 | "os": [ 95 | "aix" 96 | ], 97 | "engines": { 98 | "node": ">=12" 99 | } 100 | }, 101 | "node_modules/@esbuild/android-arm": { 102 | "version": "0.21.5", 103 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", 104 | "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", 105 | "cpu": [ 106 | "arm" 107 | ], 108 | "dev": true, 109 | "license": "MIT", 110 | "optional": true, 111 | "os": [ 112 | "android" 113 | ], 114 | "engines": { 115 | "node": ">=12" 116 | } 117 | }, 118 | "node_modules/@esbuild/android-arm64": { 119 | "version": "0.21.5", 120 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", 121 | "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", 122 | "cpu": [ 123 | "arm64" 124 | ], 125 | "dev": true, 126 | "license": "MIT", 127 | "optional": true, 128 | "os": [ 129 | "android" 130 | ], 131 | "engines": { 132 | "node": ">=12" 133 | } 134 | }, 135 | "node_modules/@esbuild/android-x64": { 136 | "version": "0.21.5", 137 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", 138 | "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", 139 | "cpu": [ 140 | "x64" 141 | ], 142 | "dev": true, 143 | "license": "MIT", 144 | "optional": true, 145 | "os": [ 146 | "android" 147 | ], 148 | "engines": { 149 | "node": ">=12" 150 | } 151 | }, 152 | "node_modules/@esbuild/darwin-arm64": { 153 | "version": "0.21.5", 154 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", 155 | "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", 156 | "cpu": [ 157 | "arm64" 158 | ], 159 | "dev": true, 160 | "license": "MIT", 161 | "optional": true, 162 | "os": [ 163 | "darwin" 164 | ], 165 | "engines": { 166 | "node": ">=12" 167 | } 168 | }, 169 | "node_modules/@esbuild/darwin-x64": { 170 | "version": "0.21.5", 171 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", 172 | "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", 173 | "cpu": [ 174 | "x64" 175 | ], 176 | "dev": true, 177 | "license": "MIT", 178 | "optional": true, 179 | "os": [ 180 | "darwin" 181 | ], 182 | "engines": { 183 | "node": ">=12" 184 | } 185 | }, 186 | "node_modules/@esbuild/freebsd-arm64": { 187 | "version": "0.21.5", 188 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", 189 | "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", 190 | "cpu": [ 191 | "arm64" 192 | ], 193 | "dev": true, 194 | "license": "MIT", 195 | "optional": true, 196 | "os": [ 197 | "freebsd" 198 | ], 199 | "engines": { 200 | "node": ">=12" 201 | } 202 | }, 203 | "node_modules/@esbuild/freebsd-x64": { 204 | "version": "0.21.5", 205 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", 206 | "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", 207 | "cpu": [ 208 | "x64" 209 | ], 210 | "dev": true, 211 | "license": "MIT", 212 | "optional": true, 213 | "os": [ 214 | "freebsd" 215 | ], 216 | "engines": { 217 | "node": ">=12" 218 | } 219 | }, 220 | "node_modules/@esbuild/linux-arm": { 221 | "version": "0.21.5", 222 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", 223 | "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", 224 | "cpu": [ 225 | "arm" 226 | ], 227 | "dev": true, 228 | "license": "MIT", 229 | "optional": true, 230 | "os": [ 231 | "linux" 232 | ], 233 | "engines": { 234 | "node": ">=12" 235 | } 236 | }, 237 | "node_modules/@esbuild/linux-arm64": { 238 | "version": "0.21.5", 239 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", 240 | "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", 241 | "cpu": [ 242 | "arm64" 243 | ], 244 | "dev": true, 245 | "license": "MIT", 246 | "optional": true, 247 | "os": [ 248 | "linux" 249 | ], 250 | "engines": { 251 | "node": ">=12" 252 | } 253 | }, 254 | "node_modules/@esbuild/linux-ia32": { 255 | "version": "0.21.5", 256 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", 257 | "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", 258 | "cpu": [ 259 | "ia32" 260 | ], 261 | "dev": true, 262 | "license": "MIT", 263 | "optional": true, 264 | "os": [ 265 | "linux" 266 | ], 267 | "engines": { 268 | "node": ">=12" 269 | } 270 | }, 271 | "node_modules/@esbuild/linux-loong64": { 272 | "version": "0.21.5", 273 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", 274 | "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", 275 | "cpu": [ 276 | "loong64" 277 | ], 278 | "dev": true, 279 | "license": "MIT", 280 | "optional": true, 281 | "os": [ 282 | "linux" 283 | ], 284 | "engines": { 285 | "node": ">=12" 286 | } 287 | }, 288 | "node_modules/@esbuild/linux-mips64el": { 289 | "version": "0.21.5", 290 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", 291 | "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", 292 | "cpu": [ 293 | "mips64el" 294 | ], 295 | "dev": true, 296 | "license": "MIT", 297 | "optional": true, 298 | "os": [ 299 | "linux" 300 | ], 301 | "engines": { 302 | "node": ">=12" 303 | } 304 | }, 305 | "node_modules/@esbuild/linux-ppc64": { 306 | "version": "0.21.5", 307 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", 308 | "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", 309 | "cpu": [ 310 | "ppc64" 311 | ], 312 | "dev": true, 313 | "license": "MIT", 314 | "optional": true, 315 | "os": [ 316 | "linux" 317 | ], 318 | "engines": { 319 | "node": ">=12" 320 | } 321 | }, 322 | "node_modules/@esbuild/linux-riscv64": { 323 | "version": "0.21.5", 324 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", 325 | "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", 326 | "cpu": [ 327 | "riscv64" 328 | ], 329 | "dev": true, 330 | "license": "MIT", 331 | "optional": true, 332 | "os": [ 333 | "linux" 334 | ], 335 | "engines": { 336 | "node": ">=12" 337 | } 338 | }, 339 | "node_modules/@esbuild/linux-s390x": { 340 | "version": "0.21.5", 341 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", 342 | "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", 343 | "cpu": [ 344 | "s390x" 345 | ], 346 | "dev": true, 347 | "license": "MIT", 348 | "optional": true, 349 | "os": [ 350 | "linux" 351 | ], 352 | "engines": { 353 | "node": ">=12" 354 | } 355 | }, 356 | "node_modules/@esbuild/linux-x64": { 357 | "version": "0.21.5", 358 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", 359 | "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", 360 | "cpu": [ 361 | "x64" 362 | ], 363 | "dev": true, 364 | "license": "MIT", 365 | "optional": true, 366 | "os": [ 367 | "linux" 368 | ], 369 | "engines": { 370 | "node": ">=12" 371 | } 372 | }, 373 | "node_modules/@esbuild/netbsd-x64": { 374 | "version": "0.21.5", 375 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", 376 | "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", 377 | "cpu": [ 378 | "x64" 379 | ], 380 | "dev": true, 381 | "license": "MIT", 382 | "optional": true, 383 | "os": [ 384 | "netbsd" 385 | ], 386 | "engines": { 387 | "node": ">=12" 388 | } 389 | }, 390 | "node_modules/@esbuild/openbsd-x64": { 391 | "version": "0.21.5", 392 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", 393 | "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", 394 | "cpu": [ 395 | "x64" 396 | ], 397 | "dev": true, 398 | "license": "MIT", 399 | "optional": true, 400 | "os": [ 401 | "openbsd" 402 | ], 403 | "engines": { 404 | "node": ">=12" 405 | } 406 | }, 407 | "node_modules/@esbuild/sunos-x64": { 408 | "version": "0.21.5", 409 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", 410 | "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", 411 | "cpu": [ 412 | "x64" 413 | ], 414 | "dev": true, 415 | "license": "MIT", 416 | "optional": true, 417 | "os": [ 418 | "sunos" 419 | ], 420 | "engines": { 421 | "node": ">=12" 422 | } 423 | }, 424 | "node_modules/@esbuild/win32-arm64": { 425 | "version": "0.21.5", 426 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", 427 | "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", 428 | "cpu": [ 429 | "arm64" 430 | ], 431 | "dev": true, 432 | "license": "MIT", 433 | "optional": true, 434 | "os": [ 435 | "win32" 436 | ], 437 | "engines": { 438 | "node": ">=12" 439 | } 440 | }, 441 | "node_modules/@esbuild/win32-ia32": { 442 | "version": "0.21.5", 443 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", 444 | "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", 445 | "cpu": [ 446 | "ia32" 447 | ], 448 | "dev": true, 449 | "license": "MIT", 450 | "optional": true, 451 | "os": [ 452 | "win32" 453 | ], 454 | "engines": { 455 | "node": ">=12" 456 | } 457 | }, 458 | "node_modules/@esbuild/win32-x64": { 459 | "version": "0.21.5", 460 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", 461 | "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", 462 | "cpu": [ 463 | "x64" 464 | ], 465 | "dev": true, 466 | "license": "MIT", 467 | "optional": true, 468 | "os": [ 469 | "win32" 470 | ], 471 | "engines": { 472 | "node": ">=12" 473 | } 474 | }, 475 | "node_modules/@jridgewell/sourcemap-codec": { 476 | "version": "1.5.0", 477 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", 478 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", 479 | "license": "MIT" 480 | }, 481 | "node_modules/@nodelib/fs.scandir": { 482 | "version": "2.1.5", 483 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 484 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 485 | "dev": true, 486 | "license": "MIT", 487 | "dependencies": { 488 | "@nodelib/fs.stat": "2.0.5", 489 | "run-parallel": "^1.1.9" 490 | }, 491 | "engines": { 492 | "node": ">= 8" 493 | } 494 | }, 495 | "node_modules/@nodelib/fs.stat": { 496 | "version": "2.0.5", 497 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 498 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 499 | "dev": true, 500 | "license": "MIT", 501 | "engines": { 502 | "node": ">= 8" 503 | } 504 | }, 505 | "node_modules/@nodelib/fs.walk": { 506 | "version": "1.2.8", 507 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 508 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 509 | "dev": true, 510 | "license": "MIT", 511 | "dependencies": { 512 | "@nodelib/fs.scandir": "2.1.5", 513 | "fastq": "^1.6.0" 514 | }, 515 | "engines": { 516 | "node": ">= 8" 517 | } 518 | }, 519 | "node_modules/@popperjs/core": { 520 | "version": "2.11.8", 521 | "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", 522 | "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", 523 | "license": "MIT", 524 | "peer": true, 525 | "funding": { 526 | "type": "opencollective", 527 | "url": "https://opencollective.com/popperjs" 528 | } 529 | }, 530 | "node_modules/@rollup/pluginutils": { 531 | "version": "5.1.3", 532 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz", 533 | "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==", 534 | "dev": true, 535 | "license": "MIT", 536 | "dependencies": { 537 | "@types/estree": "^1.0.0", 538 | "estree-walker": "^2.0.2", 539 | "picomatch": "^4.0.2" 540 | }, 541 | "engines": { 542 | "node": ">=14.0.0" 543 | }, 544 | "peerDependencies": { 545 | "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" 546 | }, 547 | "peerDependenciesMeta": { 548 | "rollup": { 549 | "optional": true 550 | } 551 | } 552 | }, 553 | "node_modules/@rollup/rollup-android-arm-eabi": { 554 | "version": "4.24.2", 555 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.2.tgz", 556 | "integrity": "sha512-ufoveNTKDg9t/b7nqI3lwbCG/9IJMhADBNjjz/Jn6LxIZxD7T5L8l2uO/wD99945F1Oo8FvgbbZJRguyk/BdzA==", 557 | "cpu": [ 558 | "arm" 559 | ], 560 | "dev": true, 561 | "license": "MIT", 562 | "optional": true, 563 | "os": [ 564 | "android" 565 | ] 566 | }, 567 | "node_modules/@rollup/rollup-android-arm64": { 568 | "version": "4.24.2", 569 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.2.tgz", 570 | "integrity": "sha512-iZoYCiJz3Uek4NI0J06/ZxUgwAfNzqltK0MptPDO4OR0a88R4h0DSELMsflS6ibMCJ4PnLvq8f7O1d7WexUvIA==", 571 | "cpu": [ 572 | "arm64" 573 | ], 574 | "dev": true, 575 | "license": "MIT", 576 | "optional": true, 577 | "os": [ 578 | "android" 579 | ] 580 | }, 581 | "node_modules/@rollup/rollup-darwin-arm64": { 582 | "version": "4.24.2", 583 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.2.tgz", 584 | "integrity": "sha512-/UhrIxobHYCBfhi5paTkUDQ0w+jckjRZDZ1kcBL132WeHZQ6+S5v9jQPVGLVrLbNUebdIRpIt00lQ+4Z7ys4Rg==", 585 | "cpu": [ 586 | "arm64" 587 | ], 588 | "dev": true, 589 | "license": "MIT", 590 | "optional": true, 591 | "os": [ 592 | "darwin" 593 | ] 594 | }, 595 | "node_modules/@rollup/rollup-darwin-x64": { 596 | "version": "4.24.2", 597 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.2.tgz", 598 | "integrity": "sha512-1F/jrfhxJtWILusgx63WeTvGTwE4vmsT9+e/z7cZLKU8sBMddwqw3UV5ERfOV+H1FuRK3YREZ46J4Gy0aP3qDA==", 599 | "cpu": [ 600 | "x64" 601 | ], 602 | "dev": true, 603 | "license": "MIT", 604 | "optional": true, 605 | "os": [ 606 | "darwin" 607 | ] 608 | }, 609 | "node_modules/@rollup/rollup-freebsd-arm64": { 610 | "version": "4.24.2", 611 | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.24.2.tgz", 612 | "integrity": "sha512-1YWOpFcGuC6iGAS4EI+o3BV2/6S0H+m9kFOIlyFtp4xIX5rjSnL3AwbTBxROX0c8yWtiWM7ZI6mEPTI7VkSpZw==", 613 | "cpu": [ 614 | "arm64" 615 | ], 616 | "dev": true, 617 | "license": "MIT", 618 | "optional": true, 619 | "os": [ 620 | "freebsd" 621 | ] 622 | }, 623 | "node_modules/@rollup/rollup-freebsd-x64": { 624 | "version": "4.24.2", 625 | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.24.2.tgz", 626 | "integrity": "sha512-3qAqTewYrCdnOD9Gl9yvPoAoFAVmPJsBvleabvx4bnu1Kt6DrB2OALeRVag7BdWGWLhP1yooeMLEi6r2nYSOjg==", 627 | "cpu": [ 628 | "x64" 629 | ], 630 | "dev": true, 631 | "license": "MIT", 632 | "optional": true, 633 | "os": [ 634 | "freebsd" 635 | ] 636 | }, 637 | "node_modules/@rollup/rollup-linux-arm-gnueabihf": { 638 | "version": "4.24.2", 639 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.2.tgz", 640 | "integrity": "sha512-ArdGtPHjLqWkqQuoVQ6a5UC5ebdX8INPuJuJNWRe0RGa/YNhVvxeWmCTFQ7LdmNCSUzVZzxAvUznKaYx645Rig==", 641 | "cpu": [ 642 | "arm" 643 | ], 644 | "dev": true, 645 | "license": "MIT", 646 | "optional": true, 647 | "os": [ 648 | "linux" 649 | ] 650 | }, 651 | "node_modules/@rollup/rollup-linux-arm-musleabihf": { 652 | "version": "4.24.2", 653 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.2.tgz", 654 | "integrity": "sha512-B6UHHeNnnih8xH6wRKB0mOcJGvjZTww1FV59HqJoTJ5da9LCG6R4SEBt6uPqzlawv1LoEXSS0d4fBlHNWl6iYw==", 655 | "cpu": [ 656 | "arm" 657 | ], 658 | "dev": true, 659 | "license": "MIT", 660 | "optional": true, 661 | "os": [ 662 | "linux" 663 | ] 664 | }, 665 | "node_modules/@rollup/rollup-linux-arm64-gnu": { 666 | "version": "4.24.2", 667 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.2.tgz", 668 | "integrity": "sha512-kr3gqzczJjSAncwOS6i7fpb4dlqcvLidqrX5hpGBIM1wtt0QEVtf4wFaAwVv8QygFU8iWUMYEoJZWuWxyua4GQ==", 669 | "cpu": [ 670 | "arm64" 671 | ], 672 | "dev": true, 673 | "license": "MIT", 674 | "optional": true, 675 | "os": [ 676 | "linux" 677 | ] 678 | }, 679 | "node_modules/@rollup/rollup-linux-arm64-musl": { 680 | "version": "4.24.2", 681 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.2.tgz", 682 | "integrity": "sha512-TDdHLKCWgPuq9vQcmyLrhg/bgbOvIQ8rtWQK7MRxJ9nvaxKx38NvY7/Lo6cYuEnNHqf6rMqnivOIPIQt6H2AoA==", 683 | "cpu": [ 684 | "arm64" 685 | ], 686 | "dev": true, 687 | "license": "MIT", 688 | "optional": true, 689 | "os": [ 690 | "linux" 691 | ] 692 | }, 693 | "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { 694 | "version": "4.24.2", 695 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.2.tgz", 696 | "integrity": "sha512-xv9vS648T3X4AxFFZGWeB5Dou8ilsv4VVqJ0+loOIgDO20zIhYfDLkk5xoQiej2RiSQkld9ijF/fhLeonrz2mw==", 697 | "cpu": [ 698 | "ppc64" 699 | ], 700 | "dev": true, 701 | "license": "MIT", 702 | "optional": true, 703 | "os": [ 704 | "linux" 705 | ] 706 | }, 707 | "node_modules/@rollup/rollup-linux-riscv64-gnu": { 708 | "version": "4.24.2", 709 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.2.tgz", 710 | "integrity": "sha512-tbtXwnofRoTt223WUZYiUnbxhGAOVul/3StZ947U4A5NNjnQJV5irKMm76G0LGItWs6y+SCjUn/Q0WaMLkEskg==", 711 | "cpu": [ 712 | "riscv64" 713 | ], 714 | "dev": true, 715 | "license": "MIT", 716 | "optional": true, 717 | "os": [ 718 | "linux" 719 | ] 720 | }, 721 | "node_modules/@rollup/rollup-linux-s390x-gnu": { 722 | "version": "4.24.2", 723 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.2.tgz", 724 | "integrity": "sha512-gc97UebApwdsSNT3q79glOSPdfwgwj5ELuiyuiMY3pEWMxeVqLGKfpDFoum4ujivzxn6veUPzkGuSYoh5deQ2Q==", 725 | "cpu": [ 726 | "s390x" 727 | ], 728 | "dev": true, 729 | "license": "MIT", 730 | "optional": true, 731 | "os": [ 732 | "linux" 733 | ] 734 | }, 735 | "node_modules/@rollup/rollup-linux-x64-gnu": { 736 | "version": "4.24.2", 737 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.2.tgz", 738 | "integrity": "sha512-jOG/0nXb3z+EM6SioY8RofqqmZ+9NKYvJ6QQaa9Mvd3RQxlH68/jcB/lpyVt4lCiqr04IyaC34NzhUqcXbB5FQ==", 739 | "cpu": [ 740 | "x64" 741 | ], 742 | "dev": true, 743 | "license": "MIT", 744 | "optional": true, 745 | "os": [ 746 | "linux" 747 | ] 748 | }, 749 | "node_modules/@rollup/rollup-linux-x64-musl": { 750 | "version": "4.24.2", 751 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.2.tgz", 752 | "integrity": "sha512-XAo7cJec80NWx9LlZFEJQxqKOMz/lX3geWs2iNT5CHIERLFfd90f3RYLLjiCBm1IMaQ4VOX/lTC9lWfzzQm14Q==", 753 | "cpu": [ 754 | "x64" 755 | ], 756 | "dev": true, 757 | "license": "MIT", 758 | "optional": true, 759 | "os": [ 760 | "linux" 761 | ] 762 | }, 763 | "node_modules/@rollup/rollup-win32-arm64-msvc": { 764 | "version": "4.24.2", 765 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.2.tgz", 766 | "integrity": "sha512-A+JAs4+EhsTjnPQvo9XY/DC0ztaws3vfqzrMNMKlwQXuniBKOIIvAAI8M0fBYiTCxQnElYu7mLk7JrhlQ+HeOw==", 767 | "cpu": [ 768 | "arm64" 769 | ], 770 | "dev": true, 771 | "license": "MIT", 772 | "optional": true, 773 | "os": [ 774 | "win32" 775 | ] 776 | }, 777 | "node_modules/@rollup/rollup-win32-ia32-msvc": { 778 | "version": "4.24.2", 779 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.2.tgz", 780 | "integrity": "sha512-ZhcrakbqA1SCiJRMKSU64AZcYzlZ/9M5LaYil9QWxx9vLnkQ9Vnkve17Qn4SjlipqIIBFKjBES6Zxhnvh0EAEw==", 781 | "cpu": [ 782 | "ia32" 783 | ], 784 | "dev": true, 785 | "license": "MIT", 786 | "optional": true, 787 | "os": [ 788 | "win32" 789 | ] 790 | }, 791 | "node_modules/@rollup/rollup-win32-x64-msvc": { 792 | "version": "4.24.2", 793 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.2.tgz", 794 | "integrity": "sha512-2mLH46K1u3r6uwc95hU+OR9q/ggYMpnS7pSp83Ece1HUQgF9Nh/QwTK5rcgbFnV9j+08yBrU5sA/P0RK2MSBNA==", 795 | "cpu": [ 796 | "x64" 797 | ], 798 | "dev": true, 799 | "license": "MIT", 800 | "optional": true, 801 | "os": [ 802 | "win32" 803 | ] 804 | }, 805 | "node_modules/@types/estree": { 806 | "version": "1.0.6", 807 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", 808 | "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", 809 | "dev": true, 810 | "license": "MIT" 811 | }, 812 | "node_modules/@vitejs/plugin-vue": { 813 | "version": "5.1.4", 814 | "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.1.4.tgz", 815 | "integrity": "sha512-N2XSI2n3sQqp5w7Y/AN/L2XDjBIRGqXko+eDp42sydYSBeJuSm5a1sLf8zakmo8u7tA8NmBgoDLA1HeOESjp9A==", 816 | "dev": true, 817 | "license": "MIT", 818 | "engines": { 819 | "node": "^18.0.0 || >=20.0.0" 820 | }, 821 | "peerDependencies": { 822 | "vite": "^5.0.0", 823 | "vue": "^3.2.25" 824 | } 825 | }, 826 | "node_modules/@vue/compiler-core": { 827 | "version": "3.5.12", 828 | "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.12.tgz", 829 | "integrity": "sha512-ISyBTRMmMYagUxhcpyEH0hpXRd/KqDU4ymofPgl2XAkY9ZhQ+h0ovEZJIiPop13UmR/54oA2cgMDjgroRelaEw==", 830 | "license": "MIT", 831 | "dependencies": { 832 | "@babel/parser": "^7.25.3", 833 | "@vue/shared": "3.5.12", 834 | "entities": "^4.5.0", 835 | "estree-walker": "^2.0.2", 836 | "source-map-js": "^1.2.0" 837 | } 838 | }, 839 | "node_modules/@vue/compiler-dom": { 840 | "version": "3.5.12", 841 | "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.12.tgz", 842 | "integrity": "sha512-9G6PbJ03uwxLHKQ3P42cMTi85lDRvGLB2rSGOiQqtXELat6uI4n8cNz9yjfVHRPIu+MsK6TE418Giruvgptckg==", 843 | "license": "MIT", 844 | "dependencies": { 845 | "@vue/compiler-core": "3.5.12", 846 | "@vue/shared": "3.5.12" 847 | } 848 | }, 849 | "node_modules/@vue/compiler-sfc": { 850 | "version": "3.5.12", 851 | "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.12.tgz", 852 | "integrity": "sha512-2k973OGo2JuAa5+ZlekuQJtitI5CgLMOwgl94BzMCsKZCX/xiqzJYzapl4opFogKHqwJk34vfsaKpfEhd1k5nw==", 853 | "license": "MIT", 854 | "dependencies": { 855 | "@babel/parser": "^7.25.3", 856 | "@vue/compiler-core": "3.5.12", 857 | "@vue/compiler-dom": "3.5.12", 858 | "@vue/compiler-ssr": "3.5.12", 859 | "@vue/shared": "3.5.12", 860 | "estree-walker": "^2.0.2", 861 | "magic-string": "^0.30.11", 862 | "postcss": "^8.4.47", 863 | "source-map-js": "^1.2.0" 864 | } 865 | }, 866 | "node_modules/@vue/compiler-ssr": { 867 | "version": "3.5.12", 868 | "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.12.tgz", 869 | "integrity": "sha512-eLwc7v6bfGBSM7wZOGPmRavSWzNFF6+PdRhE+VFJhNCgHiF8AM7ccoqcv5kBXA2eWUfigD7byekvf/JsOfKvPA==", 870 | "license": "MIT", 871 | "dependencies": { 872 | "@vue/compiler-dom": "3.5.12", 873 | "@vue/shared": "3.5.12" 874 | } 875 | }, 876 | "node_modules/@vue/devtools-api": { 877 | "version": "6.6.4", 878 | "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", 879 | "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", 880 | "license": "MIT" 881 | }, 882 | "node_modules/@vue/reactivity": { 883 | "version": "3.5.12", 884 | "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.12.tgz", 885 | "integrity": "sha512-UzaN3Da7xnJXdz4Okb/BGbAaomRHc3RdoWqTzlvd9+WBR5m3J39J1fGcHes7U3za0ruYn/iYy/a1euhMEHvTAg==", 886 | "license": "MIT", 887 | "dependencies": { 888 | "@vue/shared": "3.5.12" 889 | } 890 | }, 891 | "node_modules/@vue/runtime-core": { 892 | "version": "3.5.12", 893 | "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.12.tgz", 894 | "integrity": "sha512-hrMUYV6tpocr3TL3Ad8DqxOdpDe4zuQY4HPY3X/VRh+L2myQO8MFXPAMarIOSGNu0bFAjh1yBkMPXZBqCk62Uw==", 895 | "license": "MIT", 896 | "dependencies": { 897 | "@vue/reactivity": "3.5.12", 898 | "@vue/shared": "3.5.12" 899 | } 900 | }, 901 | "node_modules/@vue/runtime-dom": { 902 | "version": "3.5.12", 903 | "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.12.tgz", 904 | "integrity": "sha512-q8VFxR9A2MRfBr6/55Q3umyoN7ya836FzRXajPB6/Vvuv0zOPL+qltd9rIMzG/DbRLAIlREmnLsplEF/kotXKA==", 905 | "license": "MIT", 906 | "dependencies": { 907 | "@vue/reactivity": "3.5.12", 908 | "@vue/runtime-core": "3.5.12", 909 | "@vue/shared": "3.5.12", 910 | "csstype": "^3.1.3" 911 | } 912 | }, 913 | "node_modules/@vue/server-renderer": { 914 | "version": "3.5.12", 915 | "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.12.tgz", 916 | "integrity": "sha512-I3QoeDDeEPZm8yR28JtY+rk880Oqmj43hreIBVTicisFTx/Dl7JpG72g/X7YF8hnQD3IFhkky5i2bPonwrTVPg==", 917 | "license": "MIT", 918 | "dependencies": { 919 | "@vue/compiler-ssr": "3.5.12", 920 | "@vue/shared": "3.5.12" 921 | }, 922 | "peerDependencies": { 923 | "vue": "3.5.12" 924 | } 925 | }, 926 | "node_modules/@vue/shared": { 927 | "version": "3.5.12", 928 | "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.12.tgz", 929 | "integrity": "sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg==", 930 | "license": "MIT" 931 | }, 932 | "node_modules/@vuelidate/core": { 933 | "version": "2.0.3", 934 | "resolved": "https://registry.npmjs.org/@vuelidate/core/-/core-2.0.3.tgz", 935 | "integrity": "sha512-AN6l7KF7+mEfyWG0doT96z+47ljwPpZfi9/JrNMkOGLFv27XVZvKzRLXlmDPQjPl/wOB1GNnHuc54jlCLRNqGA==", 936 | "license": "MIT", 937 | "dependencies": { 938 | "vue-demi": "^0.13.11" 939 | }, 940 | "peerDependencies": { 941 | "@vue/composition-api": "^1.0.0-rc.1", 942 | "vue": "^2.0.0 || >=3.0.0" 943 | }, 944 | "peerDependenciesMeta": { 945 | "@vue/composition-api": { 946 | "optional": true 947 | } 948 | } 949 | }, 950 | "node_modules/@vuelidate/core/node_modules/vue-demi": { 951 | "version": "0.13.11", 952 | "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz", 953 | "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==", 954 | "hasInstallScript": true, 955 | "license": "MIT", 956 | "bin": { 957 | "vue-demi-fix": "bin/vue-demi-fix.js", 958 | "vue-demi-switch": "bin/vue-demi-switch.js" 959 | }, 960 | "engines": { 961 | "node": ">=12" 962 | }, 963 | "funding": { 964 | "url": "https://github.com/sponsors/antfu" 965 | }, 966 | "peerDependencies": { 967 | "@vue/composition-api": "^1.0.0-rc.1", 968 | "vue": "^3.0.0-0 || ^2.6.0" 969 | }, 970 | "peerDependenciesMeta": { 971 | "@vue/composition-api": { 972 | "optional": true 973 | } 974 | } 975 | }, 976 | "node_modules/@vuelidate/validators": { 977 | "version": "2.0.4", 978 | "resolved": "https://registry.npmjs.org/@vuelidate/validators/-/validators-2.0.4.tgz", 979 | "integrity": "sha512-odTxtUZ2JpwwiQ10t0QWYJkkYrfd0SyFYhdHH44QQ1jDatlZgTh/KRzrWVmn/ib9Gq7H4hFD4e8ahoo5YlUlDw==", 980 | "license": "MIT", 981 | "dependencies": { 982 | "vue-demi": "^0.13.11" 983 | }, 984 | "peerDependencies": { 985 | "@vue/composition-api": "^1.0.0-rc.1", 986 | "vue": "^2.0.0 || >=3.0.0" 987 | }, 988 | "peerDependenciesMeta": { 989 | "@vue/composition-api": { 990 | "optional": true 991 | } 992 | } 993 | }, 994 | "node_modules/@vuelidate/validators/node_modules/vue-demi": { 995 | "version": "0.13.11", 996 | "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz", 997 | "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==", 998 | "hasInstallScript": true, 999 | "license": "MIT", 1000 | "bin": { 1001 | "vue-demi-fix": "bin/vue-demi-fix.js", 1002 | "vue-demi-switch": "bin/vue-demi-switch.js" 1003 | }, 1004 | "engines": { 1005 | "node": ">=12" 1006 | }, 1007 | "funding": { 1008 | "url": "https://github.com/sponsors/antfu" 1009 | }, 1010 | "peerDependencies": { 1011 | "@vue/composition-api": "^1.0.0-rc.1", 1012 | "vue": "^3.0.0-0 || ^2.6.0" 1013 | }, 1014 | "peerDependenciesMeta": { 1015 | "@vue/composition-api": { 1016 | "optional": true 1017 | } 1018 | } 1019 | }, 1020 | "node_modules/acorn": { 1021 | "version": "8.14.0", 1022 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", 1023 | "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", 1024 | "dev": true, 1025 | "license": "MIT", 1026 | "bin": { 1027 | "acorn": "bin/acorn" 1028 | }, 1029 | "engines": { 1030 | "node": ">=0.4.0" 1031 | } 1032 | }, 1033 | "node_modules/anymatch": { 1034 | "version": "3.1.3", 1035 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 1036 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 1037 | "dev": true, 1038 | "license": "ISC", 1039 | "dependencies": { 1040 | "normalize-path": "^3.0.0", 1041 | "picomatch": "^2.0.4" 1042 | }, 1043 | "engines": { 1044 | "node": ">= 8" 1045 | } 1046 | }, 1047 | "node_modules/anymatch/node_modules/picomatch": { 1048 | "version": "2.3.1", 1049 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1050 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1051 | "dev": true, 1052 | "license": "MIT", 1053 | "engines": { 1054 | "node": ">=8.6" 1055 | }, 1056 | "funding": { 1057 | "url": "https://github.com/sponsors/jonschlinkert" 1058 | } 1059 | }, 1060 | "node_modules/asynckit": { 1061 | "version": "0.4.0", 1062 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 1063 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", 1064 | "license": "MIT" 1065 | }, 1066 | "node_modules/axios": { 1067 | "version": "1.7.7", 1068 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", 1069 | "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", 1070 | "license": "MIT", 1071 | "dependencies": { 1072 | "follow-redirects": "^1.15.6", 1073 | "form-data": "^4.0.0", 1074 | "proxy-from-env": "^1.1.0" 1075 | } 1076 | }, 1077 | "node_modules/balanced-match": { 1078 | "version": "1.0.2", 1079 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 1080 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 1081 | "dev": true, 1082 | "license": "MIT" 1083 | }, 1084 | "node_modules/binary-extensions": { 1085 | "version": "2.3.0", 1086 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", 1087 | "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", 1088 | "dev": true, 1089 | "license": "MIT", 1090 | "engines": { 1091 | "node": ">=8" 1092 | }, 1093 | "funding": { 1094 | "url": "https://github.com/sponsors/sindresorhus" 1095 | } 1096 | }, 1097 | "node_modules/bootstrap": { 1098 | "version": "5.3.3", 1099 | "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", 1100 | "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", 1101 | "funding": [ 1102 | { 1103 | "type": "github", 1104 | "url": "https://github.com/sponsors/twbs" 1105 | }, 1106 | { 1107 | "type": "opencollective", 1108 | "url": "https://opencollective.com/bootstrap" 1109 | } 1110 | ], 1111 | "license": "MIT", 1112 | "peerDependencies": { 1113 | "@popperjs/core": "^2.11.8" 1114 | } 1115 | }, 1116 | "node_modules/bootstrap-vue-next": { 1117 | "version": "0.25.10", 1118 | "resolved": "https://registry.npmjs.org/bootstrap-vue-next/-/bootstrap-vue-next-0.25.10.tgz", 1119 | "integrity": "sha512-6Q/VPkc1y0l/Go8I0SUWl++4d9WNf5UxqMkyoFDBeETyAA0elMOlhug67WbJXhWAmRuOmNwHxCZW8B944hAq4A==", 1120 | "license": "MIT", 1121 | "funding": { 1122 | "type": "opencollective", 1123 | "url": "https://opencollective.com/bootstrap-vue-next" 1124 | }, 1125 | "peerDependencies": { 1126 | "vue": "^3.5.3" 1127 | } 1128 | }, 1129 | "node_modules/brace-expansion": { 1130 | "version": "2.0.1", 1131 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 1132 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 1133 | "dev": true, 1134 | "license": "MIT", 1135 | "dependencies": { 1136 | "balanced-match": "^1.0.0" 1137 | } 1138 | }, 1139 | "node_modules/braces": { 1140 | "version": "3.0.3", 1141 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 1142 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 1143 | "dev": true, 1144 | "license": "MIT", 1145 | "dependencies": { 1146 | "fill-range": "^7.1.1" 1147 | }, 1148 | "engines": { 1149 | "node": ">=8" 1150 | } 1151 | }, 1152 | "node_modules/chokidar": { 1153 | "version": "3.6.0", 1154 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", 1155 | "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", 1156 | "dev": true, 1157 | "license": "MIT", 1158 | "dependencies": { 1159 | "anymatch": "~3.1.2", 1160 | "braces": "~3.0.2", 1161 | "glob-parent": "~5.1.2", 1162 | "is-binary-path": "~2.1.0", 1163 | "is-glob": "~4.0.1", 1164 | "normalize-path": "~3.0.0", 1165 | "readdirp": "~3.6.0" 1166 | }, 1167 | "engines": { 1168 | "node": ">= 8.10.0" 1169 | }, 1170 | "funding": { 1171 | "url": "https://paulmillr.com/funding/" 1172 | }, 1173 | "optionalDependencies": { 1174 | "fsevents": "~2.3.2" 1175 | } 1176 | }, 1177 | "node_modules/combined-stream": { 1178 | "version": "1.0.8", 1179 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 1180 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 1181 | "license": "MIT", 1182 | "dependencies": { 1183 | "delayed-stream": "~1.0.0" 1184 | }, 1185 | "engines": { 1186 | "node": ">= 0.8" 1187 | } 1188 | }, 1189 | "node_modules/confbox": { 1190 | "version": "0.1.8", 1191 | "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", 1192 | "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", 1193 | "dev": true, 1194 | "license": "MIT" 1195 | }, 1196 | "node_modules/csstype": { 1197 | "version": "3.1.3", 1198 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", 1199 | "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", 1200 | "license": "MIT" 1201 | }, 1202 | "node_modules/dayjs": { 1203 | "version": "1.11.13", 1204 | "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", 1205 | "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", 1206 | "license": "MIT" 1207 | }, 1208 | "node_modules/debug": { 1209 | "version": "4.3.7", 1210 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", 1211 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", 1212 | "dev": true, 1213 | "license": "MIT", 1214 | "dependencies": { 1215 | "ms": "^2.1.3" 1216 | }, 1217 | "engines": { 1218 | "node": ">=6.0" 1219 | }, 1220 | "peerDependenciesMeta": { 1221 | "supports-color": { 1222 | "optional": true 1223 | } 1224 | } 1225 | }, 1226 | "node_modules/deepmerge": { 1227 | "version": "4.3.1", 1228 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", 1229 | "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", 1230 | "license": "MIT", 1231 | "engines": { 1232 | "node": ">=0.10.0" 1233 | } 1234 | }, 1235 | "node_modules/delayed-stream": { 1236 | "version": "1.0.0", 1237 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 1238 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 1239 | "license": "MIT", 1240 | "engines": { 1241 | "node": ">=0.4.0" 1242 | } 1243 | }, 1244 | "node_modules/entities": { 1245 | "version": "4.5.0", 1246 | "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", 1247 | "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", 1248 | "license": "BSD-2-Clause", 1249 | "engines": { 1250 | "node": ">=0.12" 1251 | }, 1252 | "funding": { 1253 | "url": "https://github.com/fb55/entities?sponsor=1" 1254 | } 1255 | }, 1256 | "node_modules/esbuild": { 1257 | "version": "0.21.5", 1258 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", 1259 | "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", 1260 | "dev": true, 1261 | "hasInstallScript": true, 1262 | "license": "MIT", 1263 | "bin": { 1264 | "esbuild": "bin/esbuild" 1265 | }, 1266 | "engines": { 1267 | "node": ">=12" 1268 | }, 1269 | "optionalDependencies": { 1270 | "@esbuild/aix-ppc64": "0.21.5", 1271 | "@esbuild/android-arm": "0.21.5", 1272 | "@esbuild/android-arm64": "0.21.5", 1273 | "@esbuild/android-x64": "0.21.5", 1274 | "@esbuild/darwin-arm64": "0.21.5", 1275 | "@esbuild/darwin-x64": "0.21.5", 1276 | "@esbuild/freebsd-arm64": "0.21.5", 1277 | "@esbuild/freebsd-x64": "0.21.5", 1278 | "@esbuild/linux-arm": "0.21.5", 1279 | "@esbuild/linux-arm64": "0.21.5", 1280 | "@esbuild/linux-ia32": "0.21.5", 1281 | "@esbuild/linux-loong64": "0.21.5", 1282 | "@esbuild/linux-mips64el": "0.21.5", 1283 | "@esbuild/linux-ppc64": "0.21.5", 1284 | "@esbuild/linux-riscv64": "0.21.5", 1285 | "@esbuild/linux-s390x": "0.21.5", 1286 | "@esbuild/linux-x64": "0.21.5", 1287 | "@esbuild/netbsd-x64": "0.21.5", 1288 | "@esbuild/openbsd-x64": "0.21.5", 1289 | "@esbuild/sunos-x64": "0.21.5", 1290 | "@esbuild/win32-arm64": "0.21.5", 1291 | "@esbuild/win32-ia32": "0.21.5", 1292 | "@esbuild/win32-x64": "0.21.5" 1293 | } 1294 | }, 1295 | "node_modules/estree-walker": { 1296 | "version": "2.0.2", 1297 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 1298 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 1299 | "license": "MIT" 1300 | }, 1301 | "node_modules/fast-glob": { 1302 | "version": "3.3.2", 1303 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", 1304 | "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", 1305 | "dev": true, 1306 | "license": "MIT", 1307 | "dependencies": { 1308 | "@nodelib/fs.stat": "^2.0.2", 1309 | "@nodelib/fs.walk": "^1.2.3", 1310 | "glob-parent": "^5.1.2", 1311 | "merge2": "^1.3.0", 1312 | "micromatch": "^4.0.4" 1313 | }, 1314 | "engines": { 1315 | "node": ">=8.6.0" 1316 | } 1317 | }, 1318 | "node_modules/fastq": { 1319 | "version": "1.17.1", 1320 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", 1321 | "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", 1322 | "dev": true, 1323 | "license": "ISC", 1324 | "dependencies": { 1325 | "reusify": "^1.0.4" 1326 | } 1327 | }, 1328 | "node_modules/fill-range": { 1329 | "version": "7.1.1", 1330 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 1331 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 1332 | "dev": true, 1333 | "license": "MIT", 1334 | "dependencies": { 1335 | "to-regex-range": "^5.0.1" 1336 | }, 1337 | "engines": { 1338 | "node": ">=8" 1339 | } 1340 | }, 1341 | "node_modules/flatted": { 1342 | "version": "3.3.1", 1343 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", 1344 | "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", 1345 | "license": "ISC" 1346 | }, 1347 | "node_modules/follow-redirects": { 1348 | "version": "1.15.9", 1349 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", 1350 | "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", 1351 | "funding": [ 1352 | { 1353 | "type": "individual", 1354 | "url": "https://github.com/sponsors/RubenVerborgh" 1355 | } 1356 | ], 1357 | "license": "MIT", 1358 | "engines": { 1359 | "node": ">=4.0" 1360 | }, 1361 | "peerDependenciesMeta": { 1362 | "debug": { 1363 | "optional": true 1364 | } 1365 | } 1366 | }, 1367 | "node_modules/form-data": { 1368 | "version": "4.0.1", 1369 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", 1370 | "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", 1371 | "license": "MIT", 1372 | "dependencies": { 1373 | "asynckit": "^0.4.0", 1374 | "combined-stream": "^1.0.8", 1375 | "mime-types": "^2.1.12" 1376 | }, 1377 | "engines": { 1378 | "node": ">= 6" 1379 | } 1380 | }, 1381 | "node_modules/fsevents": { 1382 | "version": "2.3.3", 1383 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 1384 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 1385 | "dev": true, 1386 | "hasInstallScript": true, 1387 | "license": "MIT", 1388 | "optional": true, 1389 | "os": [ 1390 | "darwin" 1391 | ], 1392 | "engines": { 1393 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1394 | } 1395 | }, 1396 | "node_modules/glob-parent": { 1397 | "version": "5.1.2", 1398 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1399 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1400 | "dev": true, 1401 | "license": "ISC", 1402 | "dependencies": { 1403 | "is-glob": "^4.0.1" 1404 | }, 1405 | "engines": { 1406 | "node": ">= 6" 1407 | } 1408 | }, 1409 | "node_modules/is-binary-path": { 1410 | "version": "2.1.0", 1411 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 1412 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 1413 | "dev": true, 1414 | "license": "MIT", 1415 | "dependencies": { 1416 | "binary-extensions": "^2.0.0" 1417 | }, 1418 | "engines": { 1419 | "node": ">=8" 1420 | } 1421 | }, 1422 | "node_modules/is-extglob": { 1423 | "version": "2.1.1", 1424 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1425 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 1426 | "dev": true, 1427 | "license": "MIT", 1428 | "engines": { 1429 | "node": ">=0.10.0" 1430 | } 1431 | }, 1432 | "node_modules/is-glob": { 1433 | "version": "4.0.3", 1434 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1435 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1436 | "dev": true, 1437 | "license": "MIT", 1438 | "dependencies": { 1439 | "is-extglob": "^2.1.1" 1440 | }, 1441 | "engines": { 1442 | "node": ">=0.10.0" 1443 | } 1444 | }, 1445 | "node_modules/is-number": { 1446 | "version": "7.0.0", 1447 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1448 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1449 | "dev": true, 1450 | "license": "MIT", 1451 | "engines": { 1452 | "node": ">=0.12.0" 1453 | } 1454 | }, 1455 | "node_modules/local-pkg": { 1456 | "version": "0.5.0", 1457 | "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", 1458 | "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", 1459 | "dev": true, 1460 | "license": "MIT", 1461 | "dependencies": { 1462 | "mlly": "^1.4.2", 1463 | "pkg-types": "^1.0.3" 1464 | }, 1465 | "engines": { 1466 | "node": ">=14" 1467 | }, 1468 | "funding": { 1469 | "url": "https://github.com/sponsors/antfu" 1470 | } 1471 | }, 1472 | "node_modules/magic-string": { 1473 | "version": "0.30.12", 1474 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", 1475 | "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", 1476 | "license": "MIT", 1477 | "dependencies": { 1478 | "@jridgewell/sourcemap-codec": "^1.5.0" 1479 | } 1480 | }, 1481 | "node_modules/merge2": { 1482 | "version": "1.4.1", 1483 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 1484 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 1485 | "dev": true, 1486 | "license": "MIT", 1487 | "engines": { 1488 | "node": ">= 8" 1489 | } 1490 | }, 1491 | "node_modules/micromatch": { 1492 | "version": "4.0.8", 1493 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", 1494 | "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", 1495 | "dev": true, 1496 | "license": "MIT", 1497 | "dependencies": { 1498 | "braces": "^3.0.3", 1499 | "picomatch": "^2.3.1" 1500 | }, 1501 | "engines": { 1502 | "node": ">=8.6" 1503 | } 1504 | }, 1505 | "node_modules/micromatch/node_modules/picomatch": { 1506 | "version": "2.3.1", 1507 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1508 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1509 | "dev": true, 1510 | "license": "MIT", 1511 | "engines": { 1512 | "node": ">=8.6" 1513 | }, 1514 | "funding": { 1515 | "url": "https://github.com/sponsors/jonschlinkert" 1516 | } 1517 | }, 1518 | "node_modules/mime-db": { 1519 | "version": "1.52.0", 1520 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 1521 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 1522 | "license": "MIT", 1523 | "engines": { 1524 | "node": ">= 0.6" 1525 | } 1526 | }, 1527 | "node_modules/mime-types": { 1528 | "version": "2.1.35", 1529 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 1530 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 1531 | "license": "MIT", 1532 | "dependencies": { 1533 | "mime-db": "1.52.0" 1534 | }, 1535 | "engines": { 1536 | "node": ">= 0.6" 1537 | } 1538 | }, 1539 | "node_modules/minimatch": { 1540 | "version": "9.0.5", 1541 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", 1542 | "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", 1543 | "dev": true, 1544 | "license": "ISC", 1545 | "dependencies": { 1546 | "brace-expansion": "^2.0.1" 1547 | }, 1548 | "engines": { 1549 | "node": ">=16 || 14 >=14.17" 1550 | }, 1551 | "funding": { 1552 | "url": "https://github.com/sponsors/isaacs" 1553 | } 1554 | }, 1555 | "node_modules/mlly": { 1556 | "version": "1.7.2", 1557 | "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.2.tgz", 1558 | "integrity": "sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA==", 1559 | "dev": true, 1560 | "license": "MIT", 1561 | "dependencies": { 1562 | "acorn": "^8.12.1", 1563 | "pathe": "^1.1.2", 1564 | "pkg-types": "^1.2.0", 1565 | "ufo": "^1.5.4" 1566 | } 1567 | }, 1568 | "node_modules/ms": { 1569 | "version": "2.1.3", 1570 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1571 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1572 | "dev": true, 1573 | "license": "MIT" 1574 | }, 1575 | "node_modules/nanoid": { 1576 | "version": "3.3.8", 1577 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", 1578 | "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", 1579 | "funding": [ 1580 | { 1581 | "type": "github", 1582 | "url": "https://github.com/sponsors/ai" 1583 | } 1584 | ], 1585 | "bin": { 1586 | "nanoid": "bin/nanoid.cjs" 1587 | }, 1588 | "engines": { 1589 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 1590 | } 1591 | }, 1592 | "node_modules/normalize-path": { 1593 | "version": "3.0.0", 1594 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1595 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1596 | "dev": true, 1597 | "license": "MIT", 1598 | "engines": { 1599 | "node": ">=0.10.0" 1600 | } 1601 | }, 1602 | "node_modules/pathe": { 1603 | "version": "1.1.2", 1604 | "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", 1605 | "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", 1606 | "dev": true, 1607 | "license": "MIT" 1608 | }, 1609 | "node_modules/picocolors": { 1610 | "version": "1.1.1", 1611 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 1612 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 1613 | "license": "ISC" 1614 | }, 1615 | "node_modules/picomatch": { 1616 | "version": "4.0.2", 1617 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", 1618 | "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", 1619 | "dev": true, 1620 | "license": "MIT", 1621 | "engines": { 1622 | "node": ">=12" 1623 | }, 1624 | "funding": { 1625 | "url": "https://github.com/sponsors/jonschlinkert" 1626 | } 1627 | }, 1628 | "node_modules/pkg-types": { 1629 | "version": "1.2.1", 1630 | "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.1.tgz", 1631 | "integrity": "sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==", 1632 | "dev": true, 1633 | "license": "MIT", 1634 | "dependencies": { 1635 | "confbox": "^0.1.8", 1636 | "mlly": "^1.7.2", 1637 | "pathe": "^1.1.2" 1638 | } 1639 | }, 1640 | "node_modules/postcss": { 1641 | "version": "8.4.47", 1642 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", 1643 | "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", 1644 | "funding": [ 1645 | { 1646 | "type": "opencollective", 1647 | "url": "https://opencollective.com/postcss/" 1648 | }, 1649 | { 1650 | "type": "tidelift", 1651 | "url": "https://tidelift.com/funding/github/npm/postcss" 1652 | }, 1653 | { 1654 | "type": "github", 1655 | "url": "https://github.com/sponsors/ai" 1656 | } 1657 | ], 1658 | "license": "MIT", 1659 | "dependencies": { 1660 | "nanoid": "^3.3.7", 1661 | "picocolors": "^1.1.0", 1662 | "source-map-js": "^1.2.1" 1663 | }, 1664 | "engines": { 1665 | "node": "^10 || ^12 || >=14" 1666 | } 1667 | }, 1668 | "node_modules/proxy-from-env": { 1669 | "version": "1.1.0", 1670 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 1671 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", 1672 | "license": "MIT" 1673 | }, 1674 | "node_modules/queue-microtask": { 1675 | "version": "1.2.3", 1676 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 1677 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 1678 | "dev": true, 1679 | "funding": [ 1680 | { 1681 | "type": "github", 1682 | "url": "https://github.com/sponsors/feross" 1683 | }, 1684 | { 1685 | "type": "patreon", 1686 | "url": "https://www.patreon.com/feross" 1687 | }, 1688 | { 1689 | "type": "consulting", 1690 | "url": "https://feross.org/support" 1691 | } 1692 | ], 1693 | "license": "MIT" 1694 | }, 1695 | "node_modules/readdirp": { 1696 | "version": "3.6.0", 1697 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 1698 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1699 | "dev": true, 1700 | "license": "MIT", 1701 | "dependencies": { 1702 | "picomatch": "^2.2.1" 1703 | }, 1704 | "engines": { 1705 | "node": ">=8.10.0" 1706 | } 1707 | }, 1708 | "node_modules/readdirp/node_modules/picomatch": { 1709 | "version": "2.3.1", 1710 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1711 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1712 | "dev": true, 1713 | "license": "MIT", 1714 | "engines": { 1715 | "node": ">=8.6" 1716 | }, 1717 | "funding": { 1718 | "url": "https://github.com/sponsors/jonschlinkert" 1719 | } 1720 | }, 1721 | "node_modules/reusify": { 1722 | "version": "1.0.4", 1723 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 1724 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 1725 | "dev": true, 1726 | "license": "MIT", 1727 | "engines": { 1728 | "iojs": ">=1.0.0", 1729 | "node": ">=0.10.0" 1730 | } 1731 | }, 1732 | "node_modules/rollup": { 1733 | "version": "4.24.2", 1734 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.2.tgz", 1735 | "integrity": "sha512-do/DFGq5g6rdDhdpPq5qb2ecoczeK6y+2UAjdJ5trjQJj5f1AiVdLRWRc9A9/fFukfvJRgM0UXzxBIYMovm5ww==", 1736 | "dev": true, 1737 | "license": "MIT", 1738 | "dependencies": { 1739 | "@types/estree": "1.0.6" 1740 | }, 1741 | "bin": { 1742 | "rollup": "dist/bin/rollup" 1743 | }, 1744 | "engines": { 1745 | "node": ">=18.0.0", 1746 | "npm": ">=8.0.0" 1747 | }, 1748 | "optionalDependencies": { 1749 | "@rollup/rollup-android-arm-eabi": "4.24.2", 1750 | "@rollup/rollup-android-arm64": "4.24.2", 1751 | "@rollup/rollup-darwin-arm64": "4.24.2", 1752 | "@rollup/rollup-darwin-x64": "4.24.2", 1753 | "@rollup/rollup-freebsd-arm64": "4.24.2", 1754 | "@rollup/rollup-freebsd-x64": "4.24.2", 1755 | "@rollup/rollup-linux-arm-gnueabihf": "4.24.2", 1756 | "@rollup/rollup-linux-arm-musleabihf": "4.24.2", 1757 | "@rollup/rollup-linux-arm64-gnu": "4.24.2", 1758 | "@rollup/rollup-linux-arm64-musl": "4.24.2", 1759 | "@rollup/rollup-linux-powerpc64le-gnu": "4.24.2", 1760 | "@rollup/rollup-linux-riscv64-gnu": "4.24.2", 1761 | "@rollup/rollup-linux-s390x-gnu": "4.24.2", 1762 | "@rollup/rollup-linux-x64-gnu": "4.24.2", 1763 | "@rollup/rollup-linux-x64-musl": "4.24.2", 1764 | "@rollup/rollup-win32-arm64-msvc": "4.24.2", 1765 | "@rollup/rollup-win32-ia32-msvc": "4.24.2", 1766 | "@rollup/rollup-win32-x64-msvc": "4.24.2", 1767 | "fsevents": "~2.3.2" 1768 | } 1769 | }, 1770 | "node_modules/run-parallel": { 1771 | "version": "1.2.0", 1772 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 1773 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 1774 | "dev": true, 1775 | "funding": [ 1776 | { 1777 | "type": "github", 1778 | "url": "https://github.com/sponsors/feross" 1779 | }, 1780 | { 1781 | "type": "patreon", 1782 | "url": "https://www.patreon.com/feross" 1783 | }, 1784 | { 1785 | "type": "consulting", 1786 | "url": "https://feross.org/support" 1787 | } 1788 | ], 1789 | "license": "MIT", 1790 | "dependencies": { 1791 | "queue-microtask": "^1.2.2" 1792 | } 1793 | }, 1794 | "node_modules/source-map-js": { 1795 | "version": "1.2.1", 1796 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", 1797 | "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", 1798 | "license": "BSD-3-Clause", 1799 | "engines": { 1800 | "node": ">=0.10.0" 1801 | } 1802 | }, 1803 | "node_modules/to-regex-range": { 1804 | "version": "5.0.1", 1805 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1806 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1807 | "dev": true, 1808 | "license": "MIT", 1809 | "dependencies": { 1810 | "is-number": "^7.0.0" 1811 | }, 1812 | "engines": { 1813 | "node": ">=8.0" 1814 | } 1815 | }, 1816 | "node_modules/ufo": { 1817 | "version": "1.5.4", 1818 | "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", 1819 | "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", 1820 | "dev": true, 1821 | "license": "MIT" 1822 | }, 1823 | "node_modules/unplugin": { 1824 | "version": "1.14.1", 1825 | "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.14.1.tgz", 1826 | "integrity": "sha512-lBlHbfSFPToDYp9pjXlUEFVxYLaue9f9T1HC+4OHlmj+HnMDdz9oZY+erXfoCe/5V/7gKUSY2jpXPb9S7f0f/w==", 1827 | "dev": true, 1828 | "license": "MIT", 1829 | "dependencies": { 1830 | "acorn": "^8.12.1", 1831 | "webpack-virtual-modules": "^0.6.2" 1832 | }, 1833 | "engines": { 1834 | "node": ">=14.0.0" 1835 | }, 1836 | "peerDependencies": { 1837 | "webpack-sources": "^3" 1838 | }, 1839 | "peerDependenciesMeta": { 1840 | "webpack-sources": { 1841 | "optional": true 1842 | } 1843 | } 1844 | }, 1845 | "node_modules/unplugin-vue-components": { 1846 | "version": "0.27.4", 1847 | "resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.27.4.tgz", 1848 | "integrity": "sha512-1XVl5iXG7P1UrOMnaj2ogYa5YTq8aoh5jwDPQhemwO/OrXW+lPQKDXd1hMz15qxQPxgb/XXlbgo3HQ2rLEbmXQ==", 1849 | "dev": true, 1850 | "license": "MIT", 1851 | "dependencies": { 1852 | "@antfu/utils": "^0.7.10", 1853 | "@rollup/pluginutils": "^5.1.0", 1854 | "chokidar": "^3.6.0", 1855 | "debug": "^4.3.6", 1856 | "fast-glob": "^3.3.2", 1857 | "local-pkg": "^0.5.0", 1858 | "magic-string": "^0.30.11", 1859 | "minimatch": "^9.0.5", 1860 | "mlly": "^1.7.1", 1861 | "unplugin": "^1.12.1" 1862 | }, 1863 | "engines": { 1864 | "node": ">=14" 1865 | }, 1866 | "funding": { 1867 | "url": "https://github.com/sponsors/antfu" 1868 | }, 1869 | "peerDependencies": { 1870 | "@babel/parser": "^7.15.8", 1871 | "@nuxt/kit": "^3.2.2", 1872 | "vue": "2 || 3" 1873 | }, 1874 | "peerDependenciesMeta": { 1875 | "@babel/parser": { 1876 | "optional": true 1877 | }, 1878 | "@nuxt/kit": { 1879 | "optional": true 1880 | } 1881 | } 1882 | }, 1883 | "node_modules/vite": { 1884 | "version": "5.4.14", 1885 | "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz", 1886 | "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==", 1887 | "dev": true, 1888 | "license": "MIT", 1889 | "dependencies": { 1890 | "esbuild": "^0.21.3", 1891 | "postcss": "^8.4.43", 1892 | "rollup": "^4.20.0" 1893 | }, 1894 | "bin": { 1895 | "vite": "bin/vite.js" 1896 | }, 1897 | "engines": { 1898 | "node": "^18.0.0 || >=20.0.0" 1899 | }, 1900 | "funding": { 1901 | "url": "https://github.com/vitejs/vite?sponsor=1" 1902 | }, 1903 | "optionalDependencies": { 1904 | "fsevents": "~2.3.3" 1905 | }, 1906 | "peerDependencies": { 1907 | "@types/node": "^18.0.0 || >=20.0.0", 1908 | "less": "*", 1909 | "lightningcss": "^1.21.0", 1910 | "sass": "*", 1911 | "sass-embedded": "*", 1912 | "stylus": "*", 1913 | "sugarss": "*", 1914 | "terser": "^5.4.0" 1915 | }, 1916 | "peerDependenciesMeta": { 1917 | "@types/node": { 1918 | "optional": true 1919 | }, 1920 | "less": { 1921 | "optional": true 1922 | }, 1923 | "lightningcss": { 1924 | "optional": true 1925 | }, 1926 | "sass": { 1927 | "optional": true 1928 | }, 1929 | "sass-embedded": { 1930 | "optional": true 1931 | }, 1932 | "stylus": { 1933 | "optional": true 1934 | }, 1935 | "sugarss": { 1936 | "optional": true 1937 | }, 1938 | "terser": { 1939 | "optional": true 1940 | } 1941 | } 1942 | }, 1943 | "node_modules/vue": { 1944 | "version": "3.5.12", 1945 | "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.12.tgz", 1946 | "integrity": "sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg==", 1947 | "license": "MIT", 1948 | "dependencies": { 1949 | "@vue/compiler-dom": "3.5.12", 1950 | "@vue/compiler-sfc": "3.5.12", 1951 | "@vue/runtime-dom": "3.5.12", 1952 | "@vue/server-renderer": "3.5.12", 1953 | "@vue/shared": "3.5.12" 1954 | }, 1955 | "peerDependencies": { 1956 | "typescript": "*" 1957 | }, 1958 | "peerDependenciesMeta": { 1959 | "typescript": { 1960 | "optional": true 1961 | } 1962 | } 1963 | }, 1964 | "node_modules/vue-router": { 1965 | "version": "4.4.5", 1966 | "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.4.5.tgz", 1967 | "integrity": "sha512-4fKZygS8cH1yCyuabAXGUAsyi1b2/o/OKgu/RUb+znIYOxPRxdkytJEx+0wGcpBE1pX6vUgh5jwWOKRGvuA/7Q==", 1968 | "license": "MIT", 1969 | "dependencies": { 1970 | "@vue/devtools-api": "^6.6.4" 1971 | }, 1972 | "funding": { 1973 | "url": "https://github.com/sponsors/posva" 1974 | }, 1975 | "peerDependencies": { 1976 | "vue": "^3.2.0" 1977 | } 1978 | }, 1979 | "node_modules/vuex": { 1980 | "version": "4.0.2", 1981 | "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz", 1982 | "integrity": "sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==", 1983 | "license": "MIT", 1984 | "dependencies": { 1985 | "@vue/devtools-api": "^6.0.0-beta.11" 1986 | }, 1987 | "peerDependencies": { 1988 | "vue": "^3.0.2" 1989 | } 1990 | }, 1991 | "node_modules/vuex-persist": { 1992 | "version": "3.1.3", 1993 | "resolved": "https://registry.npmjs.org/vuex-persist/-/vuex-persist-3.1.3.tgz", 1994 | "integrity": "sha512-QWOpP4SxmJDC5Y1+0+Yl/F4n7z27syd1St/oP+IYCGe0X0GFio0Zan6kngZFufdIhJm+5dFGDo3VG5kdkCGeRQ==", 1995 | "license": "MIT", 1996 | "dependencies": { 1997 | "deepmerge": "^4.2.2", 1998 | "flatted": "^3.0.5" 1999 | }, 2000 | "peerDependencies": { 2001 | "vuex": ">=2.5" 2002 | } 2003 | }, 2004 | "node_modules/webpack-virtual-modules": { 2005 | "version": "0.6.2", 2006 | "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", 2007 | "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", 2008 | "dev": true, 2009 | "license": "MIT" 2010 | } 2011 | } 2012 | } 2013 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "@vuelidate/core": "^2.0.3", 13 | "@vuelidate/validators": "^2.0.4", 14 | "axios": "^1.7.7", 15 | "bootstrap": "^5.3.3", 16 | "bootstrap-vue-next": "^0.25.10", 17 | "dayjs": "^1.11.13", 18 | "vue": "^3.5.12", 19 | "vue-router": "^4.4.5", 20 | "vuex": "^4.0.2", 21 | "vuex-persist": "^3.1.3" 22 | }, 23 | "devDependencies": { 24 | "@vitejs/plugin-vue": "^5.1.4", 25 | "unplugin-vue-components": "^0.27.4", 26 | "vite": "^5.4.14" 27 | } 28 | } -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sinisaos/drf-vue/7c879b5983e32a49b0952247a5fb79747b9bdf09/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/src/App.vue: -------------------------------------------------------------------------------- 1 | 62 | 63 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /frontend/src/components/accounts/Login.vue: -------------------------------------------------------------------------------- 1 | 62 | 63 | 106 | -------------------------------------------------------------------------------- /frontend/src/components/accounts/Profile.vue: -------------------------------------------------------------------------------- 1 | 67 | 68 | -------------------------------------------------------------------------------- /frontend/src/components/accounts/Register.vue: -------------------------------------------------------------------------------- 1 | 117 | 118 | 175 | -------------------------------------------------------------------------------- /frontend/src/components/questions/Categories.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 46 | 47 | -------------------------------------------------------------------------------- /frontend/src/components/questions/CreateQuestion.vue: -------------------------------------------------------------------------------- 1 | 86 | 87 | 146 | -------------------------------------------------------------------------------- /frontend/src/components/questions/ProfileAnswers.vue: -------------------------------------------------------------------------------- 1 | 83 | 84 | 142 | 143 | 163 | -------------------------------------------------------------------------------- /frontend/src/components/questions/ProfileAnswersEdit.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 133 | -------------------------------------------------------------------------------- /frontend/src/components/questions/ProfileQuestions.vue: -------------------------------------------------------------------------------- 1 | 88 | 89 | 150 | 151 | 175 | -------------------------------------------------------------------------------- /frontend/src/components/questions/ProfileQuestionsEdit.vue: -------------------------------------------------------------------------------- 1 | 70 | 71 | 156 | -------------------------------------------------------------------------------- /frontend/src/components/questions/Question.vue: -------------------------------------------------------------------------------- 1 | 161 | 162 | -------------------------------------------------------------------------------- /frontend/src/components/questions/Questions.vue: -------------------------------------------------------------------------------- 1 | 148 | 149 | 324 | 325 | 345 | -------------------------------------------------------------------------------- /frontend/src/components/questions/QuestionsByTag.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 85 | 86 | 91 | -------------------------------------------------------------------------------- /frontend/src/components/questions/QuestionsOpen.vue: -------------------------------------------------------------------------------- 1 | 149 | 150 | 320 | 321 | 341 | -------------------------------------------------------------------------------- /frontend/src/components/questions/QuestionsSolved.vue: -------------------------------------------------------------------------------- 1 | 147 | 148 | 318 | 319 | 339 | -------------------------------------------------------------------------------- /frontend/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import { createBootstrap } from 'bootstrap-vue-next' 3 | import router from "./router" 4 | import store from "./store" 5 | import axios from 'axios' 6 | import App from './App.vue' 7 | 8 | // Add the necessary CSS 9 | import 'bootstrap/dist/css/bootstrap.css' 10 | import 'bootstrap-vue-next/dist/bootstrap-vue-next.css' 11 | 12 | axios.defaults.withCredentials = true 13 | axios.defaults.baseURL = "http://localhost:8000" 14 | 15 | const app = createApp(App) 16 | app.use(createBootstrap()) 17 | app.use(store) 18 | app.use(router) 19 | app.mount('#app') 20 | -------------------------------------------------------------------------------- /frontend/src/router/index.js: -------------------------------------------------------------------------------- 1 | import { createMemoryHistory, createRouter } from 'vue-router' 2 | import store from '../store/index.js' 3 | import Home from '../views/Home.vue' 4 | import Login from '../components/accounts/Login.vue' 5 | import Register from '../components/accounts/Register.vue' 6 | import Profile from '../components/accounts/Profile.vue' 7 | import Questions from '../components/questions/Questions.vue' 8 | import QuestionsOpen from '../components/questions/QuestionsOpen.vue' 9 | import QuestionsSolved from '../components/questions/QuestionsSolved.vue' 10 | import Question from '../components/questions/Question.vue' 11 | import CreateQuestion from '../components/questions/CreateQuestion.vue' 12 | import QuestionsByTag from '../components/questions/QuestionsByTag.vue' 13 | import Categories from '../components/questions/Categories.vue' 14 | import ProfileQuestions from '../components/questions/ProfileQuestions.vue' 15 | import ProfileQuestionsEdit from '../components/questions/ProfileQuestionsEdit.vue' 16 | import ProfileAnswers from '../components/questions/ProfileAnswers.vue' 17 | import ProfileAnswersEdit from '../components/questions/ProfileAnswersEdit.vue' 18 | 19 | 20 | 21 | const routes = [ 22 | { 23 | path: '/', 24 | name: 'home', 25 | component: Home 26 | }, 27 | { 28 | path: '/login', 29 | name: 'login', 30 | component: Login 31 | }, 32 | { 33 | path: '/register', 34 | name: 'register', 35 | component: Register 36 | }, 37 | { 38 | path: '/profile/:name', 39 | name: 'profile', 40 | component: Profile, 41 | meta: { 42 | requiresAuth: true 43 | } 44 | }, 45 | { 46 | path: '/profile/:name/questions', 47 | name: 'profileQuestions', 48 | component: ProfileQuestions, 49 | meta: { 50 | requiresAuth: true 51 | } 52 | }, 53 | { 54 | path: '/profile/:name/answers', 55 | name: 'profileAnswers', 56 | component: ProfileAnswers, 57 | meta: { 58 | requiresAuth: true 59 | } 60 | }, 61 | { 62 | path: '/profile/:name/questions/question-edit/:id/:title/:content', 63 | name: 'profileQuestionsEdit', 64 | component: ProfileQuestionsEdit, 65 | meta: { 66 | requiresAuth: true 67 | } 68 | }, 69 | { 70 | path: '/profile/:name/questions/answer-edit/:id/:content', 71 | name: 'profileAnswersEdit', 72 | component: ProfileAnswersEdit, 73 | meta: { 74 | requiresAuth: true 75 | } 76 | }, 77 | { 78 | path: '/questions', 79 | name: 'questions', 80 | component: Questions 81 | }, 82 | { 83 | path: '/questions/open', 84 | name: 'questionsOpen', 85 | component: QuestionsOpen 86 | }, 87 | { 88 | path: '/questions/solved', 89 | name: 'questionsSolved', 90 | component: QuestionsSolved 91 | }, 92 | { 93 | path: '/questions/:id/:slug', 94 | name: 'question', 95 | component: Question 96 | }, 97 | { 98 | path: '/create', 99 | name: 'createQuestion', 100 | component: CreateQuestion, 101 | meta: { 102 | requiresAuth: true 103 | } 104 | }, 105 | { 106 | path: '/questions/tags/:name', 107 | name: 'questionsByTag', 108 | component: QuestionsByTag 109 | }, 110 | { 111 | path: '/categories', 112 | name: 'categories', 113 | component: Categories 114 | }, 115 | ] 116 | 117 | 118 | const router = createRouter({ 119 | history: createMemoryHistory(), 120 | routes, 121 | }) 122 | 123 | 124 | router.beforeEach((to, from, next) => { 125 | if (to.matched.some(record => record.meta.requiresAuth)) { 126 | if (store.getters.isLoggedIn) { 127 | next() 128 | return 129 | } 130 | next('/') 131 | } else { 132 | next() 133 | } 134 | }) 135 | 136 | export default router 137 | 138 | 139 | -------------------------------------------------------------------------------- /frontend/src/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore } from 'vuex' 2 | import VuexPersistence from 'vuex-persist' 3 | import axios from 'axios' 4 | 5 | const vuexLocal = new VuexPersistence({ 6 | storage: window.localStorage 7 | }) 8 | 9 | 10 | const store = createStore({ 11 | state() { 12 | return { 13 | status: '', 14 | token: localStorage.getItem('token') || '', 15 | user: [], 16 | } 17 | }, 18 | mutations: { 19 | AUTH_REQUEST(state) { 20 | state.status = 'loading' 21 | }, 22 | AUTH_SUCCES(state, token, user) { 23 | state.status = 'success' 24 | state.token = token 25 | state.user = user 26 | }, 27 | AUTH_ERROR(state) { 28 | state.status = 'error' 29 | }, 30 | LOGOUT(state) { 31 | state.status = '' 32 | state.token = '' 33 | }, 34 | DELETE_USER(state) { 35 | state.user = '' 36 | } 37 | }, 38 | actions: { 39 | login({ commit }, user) { 40 | return new Promise((resolve, reject) => { 41 | commit('AUTH_REQUEST') 42 | axios({ 43 | url: '/api/auth/login', 44 | data: user, 45 | method: 'POST' 46 | }) 47 | .then(resp => { 48 | const token = resp.data.auth_token 49 | console.log(resp.data) 50 | const user = resp.data 51 | localStorage.setItem('token', token) 52 | commit('AUTH_SUCCES', token) 53 | commit('AUTH_SUCCES', user) 54 | resolve(resp) 55 | }) 56 | .catch(err => { 57 | commit('AUTH_ERROR') 58 | localStorage.removeItem('token') 59 | reject(err) 60 | }) 61 | }) 62 | }, 63 | register({ commit }, user) { 64 | return new Promise((resolve, reject) => { 65 | commit('AUTH_REQUEST') 66 | axios({ 67 | url: '/api/auth/register', 68 | data: user, 69 | method: 'POST' 70 | }) 71 | .then(resp => { 72 | const token = resp.data.auth_token 73 | const user = resp.data 74 | localStorage.setItem('token', token) 75 | commit('AUTH_SUCCES', token) 76 | commit('AUTH_SUCCES', user) 77 | resolve(resp) 78 | }) 79 | .catch(err => { 80 | commit('AUTH_ERROR', err) 81 | localStorage.removeItem('token') 82 | reject(err) 83 | }) 84 | }) 85 | }, 86 | logout({ commit }, user) { 87 | return new Promise((resolve, reject) => { 88 | axios({ 89 | url: '/api/auth/logout', 90 | data: user, 91 | method: 'POST' 92 | }) 93 | .then(resp => { 94 | commit('LOGOUT') 95 | const token = resp.data.auth_token 96 | localStorage.removeItem('token', token) 97 | resolve(resp) 98 | }) 99 | .catch(err => { 100 | reject(err) 101 | }) 102 | }) 103 | }, 104 | delete_user({ commit, state, token, dispatch }) { 105 | const auth_token = localStorage.getItem('token', token) 106 | return new Promise((resolve, reject) => { 107 | if (confirm("Are you sure you want to delete the account!")) 108 | axios({ 109 | url: '/api/users/' + state.token.id, 110 | data: token, 111 | headers: { Authorization: 'Token ' + auth_token }, 112 | method: 'DELETE' 113 | } 114 | ) 115 | .then(resp => { 116 | commit('DELETE_USER') 117 | commit('LOGOUT') 118 | const token = resp.data.token 119 | localStorage.removeItem('token', token) 120 | dispatch('logout') 121 | resolve(resp) 122 | }) 123 | .catch(err => { 124 | console.log(auth_token); 125 | reject(err) 126 | }) 127 | }) 128 | } 129 | }, 130 | getters: { 131 | authUser: state => state.token, 132 | isLoggedIn: state => !!state.token, 133 | authStatus: state => state.status, 134 | }, 135 | plugins: [vuexLocal.plugin] 136 | }) 137 | 138 | export default store 139 | 140 | -------------------------------------------------------------------------------- /frontend/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 56 | 57 | 61 | 62 | 67 | 68 | -------------------------------------------------------------------------------- /frontend/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | import Components from 'unplugin-vue-components/vite' 4 | import { BootstrapVueNextResolver } from 'bootstrap-vue-next' 5 | 6 | // https://vite.dev/config/ 7 | export default defineConfig({ 8 | plugins: [vue(), 9 | Components({ 10 | resolvers: [BootstrapVueNextResolver()], 11 | }), 12 | ], 13 | }) 14 | --------------------------------------------------------------------------------