diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml
index b7c0102..cd5604d 100644
--- a/.github/workflows/docker-image.yml
+++ b/.github/workflows/docker-image.yml
@@ -1,35 +1,35 @@
-name: Docker Image CI
+# name: Docker Image CI
-on:
- push:
- branches: [main]
- pull_request:
- branches: [main]
+# on:
+# push:
+# branches: [main]
+# pull_request:
+# branches: [main]
-jobs:
- build-image:
- runs-on: ubuntu-latest
+# jobs:
+# build-image:
+# runs-on: ubuntu-latest
- steps:
- - name: Checkout to repository
- uses: actions/checkout@v2
+# steps:
+# - name: Checkout to repository
+# uses: actions/checkout@v2
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v2
+# - name: Set up Docker Buildx
+# uses: docker/setup-buildx-action@v2
- - name: Login to GitHub Container Registry
- uses: docker/login-action@v2
- with:
- registry: ghcr.io
- username: k1g99
- password: ${{ secrets.CR_PAT }}
+# - name: Login to GitHub Container Registry
+# uses: docker/login-action@v2
+# with:
+# registry: ghcr.io
+# username: k1g99
+# password: ${{ secrets.CR_PAT }}
- - name: Build and push container image
- uses: docker/build-push-action@v4
- with:
- context: .
- file: ./Dockerfile
- push: true
- tags: ghcr.io/fgfnet/fnet:latest
- cache-from: type=gha
- cache-to: type=gha,mode=max
+# - name: Build and push container image
+# uses: docker/build-push-action@v4
+# with:
+# context: .
+# file: ./Dockerfile
+# push: true
+# tags: ghcr.io/fgfnet/fnet:latest
+# cache-from: type=gha
+# cache-to: type=gha,mode=max
diff --git a/.gitignore b/.gitignore
index 8c2921b..3f42758 100644
--- a/.gitignore
+++ b/.gitignore
@@ -79,4 +79,5 @@ media
*.py[cod]
*$py.class
-.DS_Store
\ No newline at end of file
+.DS_Store
+.env
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index 79ce11e..49c685c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -25,6 +25,6 @@ RUN apk add --update --no-cache build-base nginx curl supervisor mysql-client ma
pip install --no-cache-dir -r /app/deploy/requirements.txt && \
apk del build-base --purge
-COPY --from=builder /build/ /app/dist
+COPY --from=builder /build/build/ /app/dist
ENTRYPOINT ["sh", "/app/deploy/entrypoint.sh" ]
\ No newline at end of file
diff --git a/backend/deploy/nginx.conf b/backend/deploy/nginx.conf
index ef0c8eb..ee9ec7a 100644
--- a/backend/deploy/nginx.conf
+++ b/backend/deploy/nginx.conf
@@ -27,7 +27,7 @@ http {
access_log /data/log/nginx_access.log main;
server {
- listen 8000 default_server;
+ listen 80 default_server;
server_name _;
location /public {
diff --git a/backend/fg/models.py b/backend/fg/models.py
index e3bdaf7..641937c 100644
--- a/backend/fg/models.py
+++ b/backend/fg/models.py
@@ -6,10 +6,10 @@
# Create your models here.
class UserManager(BaseUserManager):
user_in_migrations = True
- def create_user(self, name, student_id):
+ def create_user(self, name, student_id, campus):
try:
fg = self.model(
- name = name, student_id = student_id
+ name = name, student_id = student_id, campus= campus
)
fg.set_password(student_id)
fg.save(using=self._db)
@@ -20,7 +20,8 @@ def create_superuser(self, name, password, student_id="root"):
try:
fg = self.create_user(
name=name,
- student_id = password if password else student_id
+ student_id = password if password else student_id,
+ campus = "n"
)
fg.set_password(password)
fg.role = 'Admin'
diff --git a/backend/fg/serializers.py b/backend/fg/serializers.py
index 26bf44f..e06790b 100644
--- a/backend/fg/serializers.py
+++ b/backend/fg/serializers.py
@@ -5,7 +5,7 @@
class FGSerializer(serializers.ModelSerializer):
class Meta:
model = FG
- fields = ['id', 'name', 'student_id', 'campus', 'role']
+ fields = ['id', 'name', 'role', 'student_id', 'campus']
class CreateFGSerializer(serializers.Serializer):
name = serializers.CharField()
@@ -15,4 +15,7 @@ class CreateFGSerializer(serializers.Serializer):
class LoginSerializer(serializers.Serializer):
name = serializers.CharField()
- password = serializers.CharField()
\ No newline at end of file
+ password = serializers.CharField()
+
+class FGFileUploadSerializer(serializers.Serializer):
+ file = serializers.FileField()
\ No newline at end of file
diff --git a/backend/fg/urls/admin.py b/backend/fg/urls/admin.py
index 4a415e0..23d1f05 100644
--- a/backend/fg/urls/admin.py
+++ b/backend/fg/urls/admin.py
@@ -1,7 +1,8 @@
from django.urls import path
-from ..views.admin import FGAPI
+from ..views.admin import FGAPI, FGUploadAPI
urlpatterns = [
path('fg/', FGAPI.as_view(), name="fg_admin_api"),
+ path('fg/upload/', FGUploadAPI.as_view(), name="fg_upload_api")
]
\ No newline at end of file
diff --git a/backend/fg/views/admin.py b/backend/fg/views/admin.py
index b3d1420..d1b0f29 100644
--- a/backend/fg/views/admin.py
+++ b/backend/fg/views/admin.py
@@ -1,12 +1,19 @@
from ..models import FG
-from ..serializers import (FGSerializer, CreateFGSerializer)
+from ..serializers import (FGSerializer, CreateFGSerializer, FGFileUploadSerializer)
+from lc.serializers import LCSerializer
+from lc.models import LC
+
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.decorators import api_view
+from openpyxl import load_workbook
+from django.db import transaction, IntegrityError
+from rest_framework.exceptions import ParseError
+from django.contrib.auth.hashers import make_password
class FGAPI(APIView):
def get(self, request):
- if request.user.role != ADMIN:
+ if request.user.role != 'Admin':
return Response({"error": True, "data": "Admin role required"})
fg_id = request.GET.get("id")
error = False
@@ -43,17 +50,55 @@ def post(self, request):
student_id=data["student_id"]
)
else:
- fg = FG.objects.create_user(name=data["name"],
+ fg = FG.objects.create(name=data["name"],
student_id=data["student_id"],
campus=data["campus"]
)
- # try:
- # with transaction.atomic():
- # Freshman.objects.bulk_create()
- # except IntegrityError as e:
- # return self.Response({"data": str(e).split("\n")[1]})
-
data = FGSerializer(fg).data
return Response({"error": False, "data": data})
+
+class FGUploadAPI(APIView):
+ def post(self, request):
+ if request.user.role != "Admin":
+ return Response({"error": True, "data": "Admin role required"})
+
+ serializer = FGFileUploadSerializer(data = request.data)
+ serializer.is_valid(raise_exception=True)
+ file = serializer.validated_data['file']
+
+ rows = load_workbook(file).active.rows
+ data_list = [[cell.value for cell in row] for row in rows]
+ # remove header
+ data_list.pop(0)
+
+ # lc (LCXX), 자과fg, 자과 fg 학번, 자과 fg role, 사과fg, 사과 fg 학번, 사과 fg role, 날짜
+ lc_list = []
+
+ # 기존 data 모두 삭제
+ LC.objects.all().delete()
+ FG.objects.exclude(id=1).delete()
+
+ for data in data_list:
+ if FG.objects.filter(student_id = data[2]).exists():
+ fg_n = FG.objects.get(student_id = data[2])
+ else:
+ fg_n = FG.objects.create(name=data[1],
+ student_id=data[2],
+ campus="n",
+ password=make_password(str(data[2])))
+
+ if FG.objects.filter(student_id = data[5]).exists():
+ fg_s = FG.objects.get(student_id = data[5])
+ else:
+ fg_s = FG.objects.create(name=data[4],
+ student_id=data[5],
+ campus="s",
+ password=make_password(str(data[5])))
+
+ lc_list.append(LC.objects.create(name=data[0], fg_n_id=fg_n,
+ fg_s_id=fg_s, total=0, schedule=data[7]))
+
+ lc_success_data = LCSerializer(lc_list, many=True).data
+ return Response({"error":False, "data": lc_success_data})
\ No newline at end of file
diff --git a/backend/fnet/dev_settings.py b/backend/fnet/dev_settings.py
index 672fdfb..daf9815 100644
--- a/backend/fnet/dev_settings.py
+++ b/backend/fnet/dev_settings.py
@@ -9,12 +9,14 @@
'USER': 'fnet',
'PASSWORD': 'fnet',
'HOST': '127.0.0.1',
- 'PORT': 3306,
+ 'PORT': 1398,
}
}
DEBUG = True
+SECRET_KEY = 'django-insecure-8l87s(fcz$l*hni4bs-9)rpdhzrab3=sc(fgz=b5ecau&1k0j9'
+
ALLOWED_HOSTS = ["*"]
DATA_DIR = f"{BASE_DIR}/data/django"
\ No newline at end of file
diff --git a/backend/fnet/production_settings.py b/backend/fnet/production_settings.py
index 8907785..2d7154d 100644
--- a/backend/fnet/production_settings.py
+++ b/backend/fnet/production_settings.py
@@ -13,6 +13,8 @@
DEBUG = False
+SECRET_KEY = get_env("DJANGO_SECRET_KEY")
+
ALLOWED_HOSTS = ["*"]
DATA_DIR = "/data"
\ No newline at end of file
diff --git a/backend/fnet/settings.py b/backend/fnet/settings.py
index cf950e4..3cdcc68 100644
--- a/backend/fnet/settings.py
+++ b/backend/fnet/settings.py
@@ -27,7 +27,7 @@
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = 'django-insecure-8l87s(fcz$l*hni4bs-9)rpdhzrab3=sc(fgz=b5ecau&1k0j9'
+# SECRET_KEY = 'django-insecure-8l87s(fcz$l*hni4bs-9)rpdhzrab3=sc(fgz=b5ecau&1k0j9'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
@@ -38,8 +38,8 @@
CORS_ALLOW_CREDENTIALS = True
CSRF_TRUSTED_ORIGINS = ["127.0.0.1:8000", "localhost:8000"]
CORS_ORIGIN_WHITELIST = (
- 'http://localhost:3000',
- 'http://127.0.0.1:8000',
+ 'https://localhost:8000',
+ 'https://127.0.0.1:8000',
)
CORS_ALLOW_HEADERS = (
'access-control-allow-credentials',
@@ -119,6 +119,8 @@
),
'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.JSONParser',
+ 'rest_framework.parsers.FormParser',
+ 'rest_framework.parsers.MultiPartParser'
),
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
@@ -150,7 +152,7 @@
LANGUAGE_CODE = 'en-us'
-TIME_ZONE = 'UTC'
+TIME_ZONE = 'Asia/Seoul'
USE_I18N = True
diff --git a/backend/fnet/urls.py b/backend/fnet/urls.py
index 3908b63..b49f56e 100644
--- a/backend/fnet/urls.py
+++ b/backend/fnet/urls.py
@@ -20,12 +20,11 @@
path('admin/', admin.site.urls),
path('api/', include('fg.urls.user')),
path('api/admin/', include('fg.urls.admin')),
- # path('api/', include('freshman.urls.user')),
- # path('api/admin/', include('freshman.urls.admin')),
- # path('api/', include('lc.urls.user')),
- # path('api/admin/', include('lc.urls.admin')),
+ path('api/', include('lc.urls.user')),
+ path('api/admin/', include('lc.urls.admin')),
+ path('api/', include('freshman.urls.user')),
+ path('api/admin/', include('freshman.urls.admin')),
path('api/', include('notice.urls.user')),
path('api/admin/', include('notice.urls.admin')),
- # path('api/', include('todo.urls.user')),
- # path('api/admin/', include('todo.urls.admin')),
+ path('api/', include('todo.urls.user')),
]
\ No newline at end of file
diff --git a/backend/freshman/admin.py b/backend/freshman/admin.py
index 8c38f3f..801196f 100644
--- a/backend/freshman/admin.py
+++ b/backend/freshman/admin.py
@@ -1,3 +1,4 @@
from django.contrib import admin
-
+from .models import Freshman
# Register your models here.
+admin.site.register(Freshman)
\ No newline at end of file
diff --git a/backend/freshman/migrations/0001_initial.py b/backend/freshman/migrations/0001_initial.py
new file mode 100644
index 0000000..deebbd9
--- /dev/null
+++ b/backend/freshman/migrations/0001_initial.py
@@ -0,0 +1,27 @@
+# Generated by Django 3.2.10 on 2023-02-15 19:04
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('lc', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Freshman',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=30)),
+ ('phone_number', models.CharField(max_length=13, null=True)),
+ ('register', models.BooleanField(default=False)),
+ ('department', models.CharField(choices=[('NC', '자연과학계열'), ('EN', '공학계열'), ('SS', '사회과학계열'), ('HS', '인문과학계열')], max_length=10)),
+ ('lc', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='lc.lc')),
+ ],
+ ),
+ ]
diff --git a/backend/freshman/models.py b/backend/freshman/models.py
index 71a8362..61048ac 100644
--- a/backend/freshman/models.py
+++ b/backend/freshman/models.py
@@ -1,3 +1,28 @@
from django.db import models
+from django.db.models.deletion import CASCADE
+from django.db.models.fields import CharField, BooleanField
+from django.db.models.fields.related import ForeignKey
+from lc.models import LC
# Create your models here.
+class Freshman(models.Model):
+ NATURAL_SCIENCE = 'NC'
+ ENGINEERING = 'EN'
+ SOCIAL_SCIENCE = 'SS'
+ HUMANITIES_SCIENCE = 'HS'
+
+ DEPARTMENT_CHOICES = [
+ (NATURAL_SCIENCE, '자연과학계열'),
+ (ENGINEERING, '공학계열'),
+ (SOCIAL_SCIENCE, '사회과학계열'),
+ (HUMANITIES_SCIENCE, '인문과학계열'),
+ ]
+
+ lc = ForeignKey(LC, on_delete=CASCADE, null=True)
+ name = CharField(max_length=30)
+ phone_number = CharField(max_length=13, null=True)
+ register = BooleanField(default=False)
+ department = CharField(max_length=10, choices=DEPARTMENT_CHOICES) # n(자연과학),e(공학),s(사회과학),h(인문과학)
+
+ def __str__(self):
+ return self.name
\ No newline at end of file
diff --git a/backend/freshman/serializers.py b/backend/freshman/serializers.py
new file mode 100644
index 0000000..978c0b1
--- /dev/null
+++ b/backend/freshman/serializers.py
@@ -0,0 +1,74 @@
+from django.db import models
+from rest_framework import serializers
+from .models import Freshman
+
+class FreshmanSerializer(serializers.ModelSerializer):
+ id = serializers.IntegerField()
+ name = serializers.CharField()
+ phone_number = serializers.SerializerMethodField()
+ lc = serializers.SerializerMethodField()
+ department = serializers.SerializerMethodField()
+ register = serializers.BooleanField()
+ # register = serializers.SerializerMethodField()
+
+ class Meta:
+ model = Freshman
+ fields = ['id', 'name','phone_number', 'lc', 'register', 'department']
+
+ def get_phone_number(self, obj):
+ return obj.phone_number[9:13]
+
+ def get_lc(self, obj):
+ return obj.lc.name
+
+ def get_department(self, obj):
+ if obj.department == "EN":
+ return "공학계열"
+ elif obj.department == "NC":
+ return "자연과학계열"
+ elif obj.department == "HS":
+ return "인문과학계열"
+ elif obj.department == "SS":
+ return "사회과학계열"
+
+ # def get_register(self, obj):
+ # if obj.register:
+ # return 'O'
+ # else:
+ # return 'X'
+
+
+class FreshmanLCSerializer(serializers.ModelSerializer):
+ name = serializers.CharField()
+ lc = serializers.SerializerMethodField()
+ department = serializers.SerializerMethodField()
+ register = serializers.SerializerMethodField()
+
+ class Meta:
+ model = Freshman
+ fields = ['name', 'department', 'lc', 'register']
+
+ def get_lc(self, obj):
+ return obj.lc.name
+
+ def get_department(self, obj):
+ if obj.department == "EN":
+ return "공학"
+ elif obj.department == "NC":
+ return "자연과학"
+ elif obj.department == "HS":
+ return "인문과학"
+ elif obj.department == "SS":
+ return "사회과학"
+
+ def get_register(self, obj):
+ if obj.register:
+ return 'O'
+ else:
+ return 'X'
+
+class registerFreshmanSerializer(serializers.Serializer):
+ freshman_id = serializers.IntegerField()
+
+class FreshmanFileUploadSerializer(serializers.Serializer):
+ file = serializers.FileField()
\ No newline at end of file
diff --git a/backend/freshman/urls/admin.py b/backend/freshman/urls/admin.py
index 1500611..73293b6 100644
--- a/backend/freshman/urls/admin.py
+++ b/backend/freshman/urls/admin.py
@@ -1 +1,6 @@
-from django.urls import path
\ No newline at end of file
+from django.urls import path
+from ..views.admin import setFreshmanAPI
+
+urlpatterns = [
+ path("freshman/", setFreshmanAPI.as_view())
+]
\ No newline at end of file
diff --git a/backend/freshman/urls/user.py b/backend/freshman/urls/user.py
index 1500611..4d076f5 100644
--- a/backend/freshman/urls/user.py
+++ b/backend/freshman/urls/user.py
@@ -1 +1,7 @@
-from django.urls import path
\ No newline at end of file
+from django.urls import path
+from ..views.user import getLcMemberListAPI, getLCCountInfoAPI
+
+urlpatterns = [
+ path("freshman/", getLcMemberListAPI),
+ path("freshman/count/", getLCCountInfoAPI)
+]
\ No newline at end of file
diff --git a/backend/freshman/views/admin.py b/backend/freshman/views/admin.py
index e69de29..86e288e 100644
--- a/backend/freshman/views/admin.py
+++ b/backend/freshman/views/admin.py
@@ -0,0 +1,80 @@
+from rest_framework.exceptions import ParseError
+# from rest_framework.views import status
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from openpyxl import load_workbook
+from django.db import transaction, IntegrityError
+
+from lc.models import LC
+from freshman.models import Freshman
+from freshman.serializers import FreshmanFileUploadSerializer, FreshmanSerializer, registerFreshmanSerializer
+
+class setFreshmanAPI(APIView):
+ def get(self, request):
+ if request.user.role != "Admin":
+ return Response({"error": True, "data": "Admin role required"})
+
+ try:
+ queryset = Freshman.objects.all()
+ except Freshman.DoesNotExist:
+ return Response({"error": True, "data": "Freshman does not exist"})
+
+ data = FreshmanSerializer(queryset, many=True).data
+
+ return Response({"error": False, "data": data})
+
+ def post(self, request):
+ if request.user.role != "Admin":
+ return Response({"error": True, "data": "Admin role required"})
+
+ serializer = FreshmanFileUploadSerializer(data = request.data)
+ serializer.is_valid(raise_exception=True)
+ file = serializer.validated_data['file']
+
+ rows = load_workbook(file).active.rows
+ data_list = [[cell.value for cell in row] for row in rows]
+ # remove header
+ data_list.pop(0)
+
+ # 성명/휴대폰번호/LC/지망모집단위
+ freshman_list = []
+ department_dict = {'자연과학계열':'NC', '공학계열':'EN', '사회과학계열':'SS', '인문과학계열':'HS'}
+
+ for data in data_list:
+ lc_name = data[2]
+ try:
+ lc = LC.objects.get(name=lc_name)
+ except LC.DoesNotExist:
+ # raise ParseError("LC does not exist. Check your file again")
+ return Response({"error": True, "data": "LC does not exist. Check your file again"})
+
+ freshman_list.append(Freshman(lc=lc, name=data[0], department=department_dict[data[3]], phone_number=data[1], register=False))
+
+ # 기존 data 모두 삭제
+ Freshman.objects.all().delete()
+
+ try:
+ with transaction.atomic():
+ Freshman.objects.bulk_create(freshman_list)
+ except IntegrityError as e:
+ raise ParseError({"data": str(e).split("\n")[0]})
+
+ post_success_data = FreshmanSerializer(freshman_list, many=True).data
+ return Response({"error":False, "data": post_success_data})
+
+ def put(self, request):
+ if request.user.role != "Admin":
+ return Response({"error": True, "data": "Admin role required"})
+
+ data = request.data
+ serializer = registerFreshmanSerializer(data=data)
+ serializer.is_valid(raise_exception=True)
+
+ try:
+ freshman = Freshman.objects.get(id=data["freshman_id"])
+ except Freshman.DoesNotExist:
+ return Response({"error": True, "data": "Freshman does not exist"})
+
+ freshman.register = not freshman.register
+ freshman.save()
+ return Response({"error": False, "data": {}})
\ No newline at end of file
diff --git a/backend/freshman/views/user.py b/backend/freshman/views/user.py
index e69de29..3027384 100644
--- a/backend/freshman/views/user.py
+++ b/backend/freshman/views/user.py
@@ -0,0 +1,58 @@
+from rest_framework.response import Response
+from rest_framework.decorators import api_view
+
+from lc.models import LC
+from freshman.models import Freshman
+from freshman.serializers import FreshmanLCSerializer
+
+@api_view(['GET'])
+def getLcMemberListAPI(request):
+ # check login
+ if not request.user.is_authenticated:
+ return Response({"error": True, "data": "login required"})
+
+ fg_id = request.user.id
+ fg_role = request.user.role
+
+ lc_name = request.GET.get("lc")
+ if not lc_name:
+ return Response({"error": True, "data": "LC is required"})
+
+ try:
+ lc = LC.objects.get(name=lc_name)
+ except LC.DoesNotExist:
+ return Response({"error": True, "data": "LC does not exist"})
+
+ # Admin 제외 자기 LC만 열람 가능?
+
+ queryset = Freshman.objects.filter(lc_id=lc.id)
+ data = FreshmanLCSerializer(queryset, many=True).data
+
+ return Response({"error": False, "data": data})
+
+@api_view(['GET'])
+def getLCCountInfoAPI(request):
+ # check login
+ if not request.user.is_authenticated:
+ return Response({"error": True, "data": "login required"})
+
+ fg_id = request.user.id
+ fg_role = request.user.role
+
+ lc_name = request.GET.get("lc")
+ if not lc_name:
+ return Response({"error": True, "data": "LC is required"})
+
+ try:
+ lc = LC.objects.get(name=lc_name)
+ except LC.DoesNotExist:
+ return Response({"error": True, "data": "LC does not exist"})
+
+ # Admin 제외 자기 LC만 열람 가능?
+
+ queryset = Freshman.objects.filter(lc_id=lc.id)
+ total = queryset.count()
+ register_total = queryset.filter(register=True)
+ data = { "total" : total, "register" : register_total.count() }
+
+ return Response({"error": False, "data": data})
\ No newline at end of file
diff --git a/backend/init_db.sh b/backend/init_db.sh
index 6a1c7a0..20fc586 100755
--- a/backend/init_db.sh
+++ b/backend/init_db.sh
@@ -8,7 +8,7 @@ fi
sleep 2
docker rm -f fnet-mysql-dev
-docker run -it -d -e MYSQL_DATABASE=fnet -e MYSQL_USER=fnet -e MYSQL_PASSWORD=fnet -e MYSQL_ROOT_PASSWORD=root -p 127.0.0.1:1398:1398 --name fnet-mysql-dev mysql:8.0.27
+docker run -it -d -e MYSQL_DATABASE=fnet -e MYSQL_USER=fnet -e MYSQL_PASSWORD=fnet -e MYSQL_ROOT_PASSWORD=root -p 127.0.0.1:1398:3306 --name fnet-mysql-dev mysql:8.0.27
if [ "$1" = "--migrate" ]; then
sleep 3
diff --git a/backend/lc/admin.py b/backend/lc/admin.py
index 8c38f3f..f8c415e 100644
--- a/backend/lc/admin.py
+++ b/backend/lc/admin.py
@@ -1,3 +1,6 @@
from django.contrib import admin
+from .models import LC, Schedule
# Register your models here.
+admin.site.register(Schedule)
+admin.site.register(LC)
\ No newline at end of file
diff --git a/backend/lc/migrations/0001_initial.py b/backend/lc/migrations/0001_initial.py
new file mode 100644
index 0000000..3a0c445
--- /dev/null
+++ b/backend/lc/migrations/0001_initial.py
@@ -0,0 +1,37 @@
+# Generated by Django 3.2.10 on 2023-02-15 18:51
+
+import datetime
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Schedule',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('date', models.DateField(default=datetime.datetime.now)),
+ ('day', models.IntegerField()),
+ ],
+ ),
+ migrations.CreateModel(
+ name='LC',
+ fields=[
+ ('id', models.AutoField(primary_key=True, serialize=False)),
+ ('schedule', models.IntegerField()),
+ ('name', models.CharField(max_length=10)),
+ ('total', models.IntegerField()),
+ ('fg_n_id', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='fg_n', to=settings.AUTH_USER_MODEL)),
+ ('fg_s_id', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='fg_s', to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ ]
diff --git a/backend/lc/models.py b/backend/lc/models.py
index 71a8362..5daa608 100644
--- a/backend/lc/models.py
+++ b/backend/lc/models.py
@@ -1,3 +1,19 @@
from django.db import models
+from django.db.models.fields.related import ForeignKey
+from fg.models import FG
+from django.db.models.deletion import CASCADE
+from django.db.models.fields import CharField, AutoField, IntegerField, DateField
+from datetime import datetime
# Create your models here.
+class LC(models.Model):
+ id = models.AutoField(primary_key= True)
+ fg_n_id = ForeignKey(FG, on_delete=CASCADE, null= True, related_name='fg_n' )
+ fg_s_id = ForeignKey(FG, on_delete=CASCADE, null= True, related_name='fg_s' )
+ schedule = IntegerField()
+ name = CharField(max_length=10)
+ total = IntegerField()
+
+class Schedule(models.Model):
+ date = DateField(default=datetime.now)
+ day = IntegerField()
diff --git a/backend/lc/serializers.py b/backend/lc/serializers.py
new file mode 100644
index 0000000..0bbb4c4
--- /dev/null
+++ b/backend/lc/serializers.py
@@ -0,0 +1,22 @@
+from django.db import models
+from .models import Schedule, LC
+from rest_framework import serializers
+from fg.serializers import FGSerializer
+
+class CreateScheduleSerializer(serializers.Serializer):
+ date = serializers.DateField()
+ day = serializers.IntegerField()
+
+class LCSerializer(serializers.ModelSerializer):
+ fg_n_id = FGSerializer()
+ fg_s_id = FGSerializer()
+ class Meta:
+ model = LC
+ fields = "__all__"
+
+
+class ScheduleSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = Schedule
+ fields = "__all__"
+
\ No newline at end of file
diff --git a/backend/lc/urls/admin.py b/backend/lc/urls/admin.py
index 1500611..32a17da 100644
--- a/backend/lc/urls/admin.py
+++ b/backend/lc/urls/admin.py
@@ -1 +1,7 @@
-from django.urls import path
\ No newline at end of file
+from django.urls import path
+from ..views.admin import ScheduleAPI, LCAPI
+
+urlpatterns = [
+ path('schedule/', ScheduleAPI.as_view(), name="schedule_api"),
+ path('LC/', LCAPI.as_view(), name="lc_api")
+]
\ No newline at end of file
diff --git a/backend/lc/urls/user.py b/backend/lc/urls/user.py
index 1500611..a7f8c0d 100644
--- a/backend/lc/urls/user.py
+++ b/backend/lc/urls/user.py
@@ -1 +1,8 @@
-from django.urls import path
\ No newline at end of file
+from django.urls import path
+from ..views.user import TodayLCAPI, LCAPI, ScheduleAPI
+
+urlpatterns = [
+ path('schedule/', ScheduleAPI.as_view(), name="schedule_api"),
+ path('LC/', LCAPI.as_view(), name="LC_api"),
+ path('TodayLC/', TodayLCAPI.as_view(), name="TodayLC_api")
+]
\ No newline at end of file
diff --git a/backend/lc/views/admin.py b/backend/lc/views/admin.py
index e69de29..30cbfb3 100644
--- a/backend/lc/views/admin.py
+++ b/backend/lc/views/admin.py
@@ -0,0 +1,47 @@
+from ..models import LC, Schedule
+from ..serializers import (CreateScheduleSerializer, ScheduleSerializer, LCSerializer)
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework.decorators import api_view
+import datetime
+import dateutil.parser
+
+class LCAPI(APIView):
+ def get(self, request):
+ if request.user.role != "Admin":
+ return Response({"error": True, "data": "Admin role required"})
+ error = False
+ lc = LC.objects.all().order_by("id")
+ return Response({"error": error, "data": LCSerializer(lc, many=True).data})
+
+class ScheduleAPI(APIView):
+ def post(self, request):
+ print(request.user.role)
+ if request.user.role != "Admin":
+ return Response({"error": True, "data": "Admin role required"})
+ serializer = CreateScheduleSerializer(request.data)
+ data = serializer.data
+
+ old = Schedule.objects.filter(day=data["day"])
+ old.delete()
+
+ schedule = Schedule.objects.create(date=dateutil.parser.parse(data["date"]).date(), day = data["day"])
+ return Response({"error":False, "data": ScheduleSerializer(schedule).data})
+
+ def put(self, request):
+ data = Schedule.objects.filter()
+
+ if len(data) > 0:
+ data.delete()
+ # if request.user.role != ADMIN:1
+ # return Response({"error":True, "data":"not Admin"})
+ data = request.data["datelist"]
+ for d in data:
+ serializer = CreateScheduleSerializer(d)
+ n = 1
+ for d in data:
+ Schedule.objects.create(date=dateutil.parser.parse(d["date"]).date(), day = n)
+ n+= 1
+ return Response({"error":False, "data":None})
+
+
diff --git a/backend/lc/views/user.py b/backend/lc/views/user.py
index e69de29..6623a14 100644
--- a/backend/lc/views/user.py
+++ b/backend/lc/views/user.py
@@ -0,0 +1,55 @@
+from ..models import LC, Schedule
+from ..serializers import (CreateScheduleSerializer, ScheduleSerializer, LCSerializer)
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework.decorators import api_view
+import datetime
+import dateutil.parser
+
+class ScheduleAPI(APIView):
+ def get(self, request):
+ try:
+ queryset = Schedule.objects.all().order_by("day")
+ data = ScheduleSerializer(queryset, many = True).data
+ except Schedule.DoesNotExist:
+ return Response({"error": True, "data": "NO data"})
+ return Response({"error":False, "data":data})
+
+class TodayLCAPI(APIView):
+ def get(self, request):
+ user_campus = request.user.campus
+ current_datetime = datetime.date.today()
+ try:
+ schedule = Schedule.objects.get(date = current_datetime)
+ except Schedule.DoesNotExist:
+ return Response({"error":False, "data": None})
+ if user_campus == "n":
+ try:
+ todayLC = LC.objects.filter(schedule = schedule.day, fg_n_id = request.user)
+ except LC.DoesNotExist:
+ return Response({"error":False, "data": None})
+ else:
+ try:
+ todayLC = LC.objects.filter(schedule = schedule.day, fg_s_id = request.user)
+ except LC.DoesNotExist:
+ return Response({"error":False, "data": None})
+ return Response({"error": False, "data": LCSerializer(todayLC, many=True).data})
+
+class LCAPI(APIView):
+ def get(self, request):
+ user_campus = request.user.campus
+
+ if user_campus == "n":
+ try:
+ todayLC = LC.objects.filter(fg_n_id = request.user)
+ data = LCSerializer(todayLC, many=True).data
+
+ except LC.DoesNotExist:
+ return Response({"error":False, "data": None})
+ else:
+ try:
+ todayLC = LC.objects.filter(fg_s_id = request.user)
+ data = LCSerializer(todayLC, many=True).data
+ except LC.DoesNotExist:
+ return Response({"error":False, "data": None})
+ return Response({"error": False, "data": data})
diff --git a/backend/todo/admin.py b/backend/todo/admin.py
index 8c38f3f..28c98ee 100644
--- a/backend/todo/admin.py
+++ b/backend/todo/admin.py
@@ -1,3 +1,5 @@
from django.contrib import admin
+
+
# Register your models here.
diff --git a/backend/todo/migrations/0001_initial.py b/backend/todo/migrations/0001_initial.py
new file mode 100644
index 0000000..11e12f7
--- /dev/null
+++ b/backend/todo/migrations/0001_initial.py
@@ -0,0 +1,35 @@
+# Generated by Django 3.2.10 on 2023-02-12 14:34
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Todo',
+ fields=[
+ ('id', models.AutoField(db_column='todo_id', primary_key=True, serialize=False)),
+ ('content', models.CharField(max_length=100)),
+ ('common', models.BooleanField()),
+ ('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='created_by', to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Todo_check',
+ fields=[
+ ('id', models.AutoField(primary_key=True, serialize=False)),
+ ('check', models.BooleanField()),
+ ('fg_id', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='fg_id', to=settings.AUTH_USER_MODEL)),
+ ('todo_id', models.ForeignKey(db_column='todo_id', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='todo_id', to='todo.todo')),
+ ],
+ ),
+ ]
diff --git a/backend/todo/migrations/0002_auto_20230214_1303.py b/backend/todo/migrations/0002_auto_20230214_1303.py
new file mode 100644
index 0000000..8c5d621
--- /dev/null
+++ b/backend/todo/migrations/0002_auto_20230214_1303.py
@@ -0,0 +1,26 @@
+# Generated by Django 3.2.10 on 2023-02-14 04:03
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('todo', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='todo',
+ name='id',
+ field=models.AutoField(primary_key=True, serialize=False),
+ ),
+ migrations.AlterModelTable(
+ name='todo',
+ table='todo',
+ ),
+ migrations.AlterModelTable(
+ name='todo_check',
+ table='todo_check',
+ ),
+ ]
diff --git a/backend/todo/models.py b/backend/todo/models.py
index 71a8362..38b8a94 100644
--- a/backend/todo/models.py
+++ b/backend/todo/models.py
@@ -1,3 +1,24 @@
from django.db import models
+from django.db.models.fields.related import ForeignKey
+from fg.models import FG
+from django.db.models.deletion import CASCADE
+from django.db.models.fields import CharField, DateTimeField, AutoField, IntegerField, BooleanField
-# Create your models here.
+class Todo(models.Model):
+ id = models.AutoField(primary_key= True)
+ created_by = ForeignKey(FG, on_delete=CASCADE, null= True, related_name='created_by' )
+ content = CharField(max_length=100)
+ common = models.BooleanField()
+
+ class Meta:
+ db_table = 'todo'
+
+
+class Todo_check(models.Model):
+ id = models.AutoField(primary_key= True)
+ todo_id = ForeignKey(Todo, db_column='todo_id' ,on_delete=CASCADE, related_name='todo_id', null= True )
+ fg_id = ForeignKey(FG, on_delete=CASCADE, null= True, related_name='fg_id' )
+ check = models.BooleanField()
+
+ class Meta:
+ db_table = 'todo_check'
diff --git a/backend/todo/serializers.py b/backend/todo/serializers.py
new file mode 100644
index 0000000..7835733
--- /dev/null
+++ b/backend/todo/serializers.py
@@ -0,0 +1,39 @@
+from django.db import models
+from .models import Todo, Todo_check
+from rest_framework import serializers
+
+class CreateTodoSerializer(serializers.Serializer):
+ content = serializers.CharField()
+ common = serializers.BooleanField()
+
+class EditTodoSerializer(serializers.Serializer):
+ id = serializers.IntegerField()
+ content = serializers.CharField()
+
+class TodoSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = Todo
+ fields = "__all__"
+
+
+class TodoPlusCheckSerializer(serializers.ModelSerializer):
+ todo_id = TodoSerializer()
+ class Meta:
+ model = Todo_check
+ fields = "__all__"
+
+class TodoCheckSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = Todo_check
+ fields = "__all__"
+
+class TodoCheckSerializer(serializers.Serializer):
+ id = serializers.IntegerField()
+ check = serializers.BooleanField()
+
+class TodoAllSerializer(serializers.Serializer):
+ id = serializers.IntegerField()
+ todo_id = serializers.IntegerField()
+ content = serializers.CharField()
+ common = serializers.BooleanField()
+ check = serializers.BooleanField()
diff --git a/backend/todo/urls/admin.py b/backend/todo/urls/admin.py
deleted file mode 100644
index 1500611..0000000
--- a/backend/todo/urls/admin.py
+++ /dev/null
@@ -1 +0,0 @@
-from django.urls import path
\ No newline at end of file
diff --git a/backend/todo/urls/user.py b/backend/todo/urls/user.py
index 1500611..57ce4a9 100644
--- a/backend/todo/urls/user.py
+++ b/backend/todo/urls/user.py
@@ -1 +1,7 @@
-from django.urls import path
\ No newline at end of file
+from django.urls import path
+from ..views.user import Todo_checkAPI, TodoAPI
+
+urlpatterns = [
+ path('todocheck/', Todo_checkAPI.as_view(), name="Todocheck_api"),
+ path('todo/', TodoAPI.as_view(), name="Todo_api"),
+]
\ No newline at end of file
diff --git a/backend/todo/views/user.py b/backend/todo/views/user.py
index e69de29..1d84ccd 100644
--- a/backend/todo/views/user.py
+++ b/backend/todo/views/user.py
@@ -0,0 +1,108 @@
+from ..models import Todo, Todo_check
+from ..serializers import TodoPlusCheckSerializer,CreateTodoSerializer, TodoSerializer, EditTodoSerializer, TodoCheckSerializer, TodoAllSerializer
+from fg.models import FG
+from itertools import chain
+from rest_framework.response import Response
+from rest_framework.views import APIView
+
+
+class TodoAPI(APIView):
+ def get(self, request):
+ get_common = True if request.GET.get("common") == 'true' else False
+ try:
+ if get_common:
+ todos = TodoPlusCheckSerializer(Todo_check.objects.filter(fg_id = request.user),many= True).data
+ result = []
+ for todo in todos:
+ if todo["todo_id"]["common"] == get_common:
+ result.append(todo)
+ else:
+ todos = TodoPlusCheckSerializer(Todo_check.objects.filter(fg_id = request.user),many= True).data
+ result = []
+ for todo in todos:
+ if todo["todo_id"]["common"]== get_common:
+ result.append(todo)
+ except Todo.DoesNotExist:
+ msg = "Todo does not exist"
+ return Response({"error": True, "data": msg})
+ return Response({"error": False, "data" : result})
+
+ def post(self, request):
+ serializer = CreateTodoSerializer(data = request.data)
+ serializer.is_valid(raise_exception=True)
+ data = serializer.data
+
+ if data["common"] == False:
+ todo = Todo.objects.create(created_by = request.user,
+ content = data["content"],
+ common = False)
+ todo_check= Todo_check.objects.create(todo_id = todo,
+ fg_id = request.user,
+ check = False)
+ return Response({"error": False, "data": TodoSerializer(todo).data})
+ else:
+ try:
+ fgs = FG.objects.all()
+ except FG.DoesNotExist:
+ msg = "FG does not exist"
+ return Response({"error": True, "data": msg})
+ todo = Todo.objects.create(created_by = request.user,
+ content = data["content"],
+ common = True)
+ for fg in fgs:
+ todo_check= Todo_check.objects.create(todo_id = todo,
+ fg_id = fg,
+ check = False)
+ return Response({"error": False, "data": TodoSerializer(todo).data})
+
+ def put(self, request):
+ serializer = EditTodoSerializer(data=request.data)
+ serializer.is_valid(raise_exception=True)
+ data = serializer.data
+
+ try:
+ todo = Todo.objects.get(id = data.pop("id"))
+ except Todo.DoesNotExist:
+ msg = "Todo does not exist"
+ return Response({"error":True, "data": msg})
+
+ todo.content = data["content"]
+ todo.save()
+ return Response({"error": False, "data": TodoSerializer(todo).data})
+
+ def delete(self, request):
+ """
+ delete notice
+ """
+ error = False
+ todo_id = request.GET.get("id")
+ if not todo_id:
+ msg = "Invalid parameter, id is required"
+ error = True
+ return Response({"error": error, "data": msg})
+
+ try:
+ todo = Todo.objects.get(id=todo_id)
+ except Todo.DoesNotExist:
+ msg = "Todo does not exist"
+ error = True
+ return Response({"error": error, "data": msg})
+
+ todo.delete()
+ return Response({"error": error, "data": None})
+
+class Todo_checkAPI(APIView):
+ def put(self, request):
+ serializer = TodoCheckSerializer(data=request.data)
+ serializer.is_valid(raise_exception=True)
+ data = serializer.data
+
+ try:
+ todo_check = Todo_check.objects.get(id = data["id"])
+ except Todo_check.DoesNotExist:
+ msg = "Todo Check does not exist"
+ return Response({"error":True, "data": msg})
+
+ todo_check.check = data["check"]
+ todo_check.save()
+ return Response({"error": False, "data": TodoCheckSerializer(todo_check).data})
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index acae2d2..785bd7c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -8,25 +8,28 @@ services:
volumes:
- ./data/django:/data
ports:
- - "8000:8000"
+ - "80:80"
+ # - "8000:8000"
+ # - "8080:8080"
depends_on:
- fnet-mysql
environment:
- - MYSQL_DATABASE=fnet
- - MYSQL_USER=fnet
- - MYSQL_PASSWORD=fnet
- - DJANGO_SUPERUSER_NAME=root
- - DJANGO_SUPERUSER_PASSWORD=rootroot
+ - MYSQL_DATABASE=${MYSQL_DATABASE}
+ - MYSQL_USER=${MYSQL_USER}
+ - MYSQL_PASSWORD=${MYSQL_PASSWORD}
+ - DJANGO_SECRET_KEY=${DJANGO_SECRET_KEY}
+ - DJANGO_SUPERUSER_NAME=${DJANGO_SUPERUSER_NAME}
+ - DJANGO_SUPERUSER_PASSWORD=${DJANGO_SUPERUSER_PASSWORD}
fnet-mysql:
image: mysql
container_name: fnet-mysql
- ports:
- - "3306:3306"
+ # ports:
+ # - "3306:3306"
volumes:
- ./data/mysql:/var/lib/mysql
environment:
- - MYSQL_ROOT_PASSWORD=root
- - MYSQL_DATABASE=fnet
- - MYSQL_USER=fnet
- - MYSQL_PASSWORD=fnet
+ - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
+ - MYSQL_DATABASE=${MYSQL_DATABASE}
+ - MYSQL_USER=${MYSQL_USER}
+ - MYSQL_PASSWORD=${MYSQL_PASSWORD}
diff --git a/frontend/public/index.html b/frontend/public/index.html
index babe619..209ce92 100644
--- a/frontend/public/index.html
+++ b/frontend/public/index.html
@@ -7,6 +7,7 @@
+