Procházet zdrojové kódy

Merge remote-tracking branch 'origin/master'

zooey před 1 rokem
rodič
revize
d6c58932b5
5 změnil soubory, kde provedl 467 přidání a 48 odebrání
  1. 3 1
      app/api/__init__.py
  2. 288 0
      app/api/article.py
  3. 158 43
      app/api/classes.py
  4. 14 3
      app/api/news.py
  5. 4 1
      app/models/models.py

+ 3 - 1
app/api/__init__.py

@@ -5,6 +5,7 @@ from app.api.classes import classes
 from app.api.news import news
 from app.api.guidance import guidance
 from app.api.registration import registration
+from app.api.article import article
 
 routers = APIRouter()
 
@@ -12,4 +13,5 @@ routers.include_router(users, prefix="/api", tags=["登入/註冊"])
 routers.include_router(classes, prefix="/api", tags=["課程列表"])
 routers.include_router(news, prefix="/api", tags=["最新消息"])
 routers.include_router(guidance, prefix="/api", tags=["輔導團紀錄"])
-routers.include_router(registration, prefix="/api", tags=["報名課程"])
+routers.include_router(registration, prefix="/api", tags=["報名課程"])
+routers.include_router(article, prefix="/api", tags=["文章"])

+ 288 - 0
app/api/article.py

@@ -0,0 +1,288 @@
+from fastapi import APIRouter, Form, Depends, HTTPException, File, UploadFile
+from typing import List,Optional,Union
+from fastapi.responses import FileResponse
+from random import randint
+from fastapi.security import OAuth2PasswordRequestForm
+from app.models.models import User,Article_list
+from app.api import deps
+from sqlalchemy.orm import Session
+from typing import Any, Dict
+import secrets
+from fastapi_login.exceptions import InvalidCredentialsException
+from fastapi_login import LoginManager
+from datetime import timedelta,datetime
+from jose import jwt
+from emails.template import JinjaTemplate
+from tortoise.queryset import Q
+from fastapi.responses import HTMLResponse
+
+article = APIRouter()
+
+IMAGEDIR = "/var/www/ntcri/ntcri/assets/article_files/"
+IMAGEDIR_short = "assets/article_files/"
+
+async def create_upload_files(files:Optional[List[UploadFile]] = File(None)):
+    files_url = {}
+    if files :
+        file_num = 1
+        print(file_num)
+        for file in files:
+            contents = await file.read()
+
+            #save the file
+            with open(f"{IMAGEDIR}{file.filename}", "wb") as f:
+                f.write(contents)
+                file_name = "file" + str(file_num)
+                print(file_name)
+                files_url[file_name]=f"{IMAGEDIR_short}{file.filename}"       
+                file_num=file_num+1 
+
+    return files_url
+
+@article.get("/get_article")
+async def get_article(
+    article_id : Optional[int] = None,
+    group_id : Optional[int] = None,
+    group_sort : Optional[str] = None,
+    category : Optional[str] = None,
+    tags : Optional[str] = None,
+    page_num : Optional[int] = None,
+    page_amount : Optional[int] = None
+):
+    try:
+        article_list = Article_list.filter(is_del = 0).all()
+
+        if group_sort:
+            article_list = article_list.filter(group_sort = group_sort).all()
+        
+        if category:
+            article_list = article_list.filter(Q(category__icontains=category)).all()
+
+        if tags:
+            article_list = article_list.filter(Q(tags__icontains=category)).all()
+        
+        if article_id :
+            article_list = article_list.filter(id = article_id).all()
+
+        if group_id :
+            article_list = article_list.filter(group_id = group_id).all()
+
+        article_list = await article_list.all()
+
+        article_objs = []
+        count = 0
+        for article_obj in article_list:
+            article_tmp = {
+            "article_id": article_obj.id,
+            "title": article_obj.title,
+            "school_id" :article_obj.school_id,
+            "group_sort" :article_obj.group_sort,
+            "group_id" :article_obj.group_id,
+            "category": article_obj.category,
+            "create_time" : article_obj.create_time,
+            "click_time" : article_obj.click_time,
+            "depiction" : article_obj.depiction,
+            "content" : article_obj.content,
+            "files" : article_obj.files,
+            "vedio_url" : article_obj.vedio_url,
+            "tags" : article_obj.tags,
+            "cover_img": article_obj.cover_img,
+            "url" : article_obj.url
+            }
+            if page_num and page_amount:
+                if count < page_num*page_amount and count >= (page_num-1)*page_amount :
+                    article_objs.append(article_tmp)
+                    count += 1
+                elif  count >= page_num*page_amount: count += 1
+                else : count += 1
+            else :
+                article_objs.append(article_tmp)
+                count += 1
+
+        return {"msg": "success", "code": 200, "total_num":count,"articles": article_objs}
+    except Exception as e:
+        return {"msg": str(e), "code": 500}
+
+@article.post("/insert_article_imgs")
+async def insert_imgs(
+    files_url = Depends(create_upload_files)
+):
+    try:
+        files = str(files_url),
+        
+        return {"msg": "success", "code": 200, "url": files}
+    except Exception as e:
+        return {"msg": str(e), "code": 500}
+
+@article.post("/insert_article")
+async def insert_article(
+    title : str = Form(default=''),
+    school_id : int = Form(default=1),
+    group_id : int = Form(default=1),
+    group_sort : str = Form(default=''),
+    tags : str = Form(default='[]'),
+    category : str = Form(default=''),
+    content : str = Form(default=''),
+    depiction :str = Form(default=''),
+    vedio_url :str = Form(default=''),
+    cover_img_file:UploadFile = File(default=''),
+    url : str = Form(default='')
+):
+    try:
+        cover_img = ''
+        if cover_img_file != '':
+            contents = await cover_img_file.read()
+
+        #save the file
+            with open(f"{IMAGEDIR}{cover_img_file.filename}", "wb") as f:
+                f.write(contents)
+        
+            cover_img = f"{IMAGEDIR_short}{cover_img_file.filename}"
+
+        new_article = await Article_list.create(
+            title = title,
+            school_id = school_id,
+            group_id = group_id,
+            group_sort = group_sort,
+            create_user_id = 0,
+            create_time = datetime.now(),
+            latest_update_user_id = 0,
+            latest_update_time = datetime.now(),
+            tags = tags,
+            category = category,
+            content = content,
+            depiction = depiction,
+            vedio_url =vedio_url,
+            cover_img = cover_img,
+            click_time = 0,
+            is_del = 0,
+            url = url ,
+            files = str({})
+        )
+        
+        return {"msg": "success", "code": 200, "new_article": new_article.id}
+    except Exception as e:
+        return {"msg": str(e), "code": 500}
+    
+@article.post("/update_article")
+async def update_article(
+    article_id : int = Form(default=0),
+    title : str = Form(default=''),
+    school_id : int = Form(default=0),
+    group_id : int = Form(default=0),
+    group_sort : str = Form(default=''),
+    tags : str = Form(default='[]'),
+    category : str = Form(default=''),
+    content : str = Form(default=''),
+    depiction :str = Form(default=''),
+    vedio_url :str = Form(default=''),
+    url :str = Form(default=''),
+    cover_img_file:UploadFile = File(default='')
+):
+    try:
+        if article_id == 0 :
+            return {"msg": "no ID"}
+        
+        article_obj = await Article_list.get(id=article_id)
+
+        if title.strip() != '':
+            article_obj.title = title
+
+        if school_id != 0:
+            article_obj.school_id = school_id
+
+        if group_id != 0:
+            article_obj.group_id = group_id
+
+        if group_sort.strip() != '':
+            article_obj.group_sort = group_sort
+            print(group_sort +"change")
+        
+        if category.strip() != '':
+            article_obj.category = category
+
+        if content.strip() != '':
+            article_obj.content = content
+
+        if depiction.strip() != '':
+            article_obj.depiction = depiction
+
+        if vedio_url.strip() != '':
+            article_obj.vedio_url = vedio_url
+
+        if tags != '[]':
+            article_obj.tags = tags
+
+        if url != '[]':
+            article_obj.url = url
+
+        
+        if cover_img_file != '':
+            contents = await cover_img_file.read()
+
+            with open(f"{IMAGEDIR}{cover_img_file.filename}", "wb") as f:
+                f.write(contents)
+        
+            article_obj.cover_img = f"{IMAGEDIR_short}{cover_img_file.filename}"
+        
+        
+        await article_obj.save()
+        
+        return {"msg": "success", "code": 200}
+    except Exception as e:
+        return {"msg": str(e), "code": 500}
+
+@article.post("/delete_article")
+async def delete_article(id: int = 0):
+    if id != 0:
+        await Article_list.filter(id=id).delete()
+        return {"msg": "success", "code": 200}
+    else :
+        return {"msg": "please input ID", "code": 200}
+    
+@article.get("/search_article_like")
+async def search_article_like(keyword: str,page_num : Optional[int] = None,
+    page_amount : Optional[int] = None):
+    try:
+        article_list = await Article_list.filter(
+            Q(title__icontains=keyword)|
+            Q(category__icontains=keyword)|
+            Q(content__icontains=keyword)|
+            Q(depiction__icontains=keyword)|
+            Q(tags__icontains=keyword)
+                ).all()
+        
+        article_objs = []
+        count = 0
+        for article_obj in article_list:
+            article_tmp = {
+            "article_id": article_obj.id,
+            "title": article_obj.title,
+            "school_id" :article_obj.school_id,
+            "group_sort" :article_obj.group_sort,
+            "group_id" :article_obj.group_id,
+            "category": article_obj.category,
+            "create_time" : article_obj.create_time,
+            "click_time" : article_obj.click_time,
+            "depiction" : article_obj.depiction,
+            "content" : article_obj.content,
+            "files" : article_obj.files,
+            "vedio_url" : article_obj.vedio_url,
+            "tags" : article_obj.tags,
+            "cover_img": article_obj.cover_img,
+            "url" : article_obj.url
+        }
+            if page_num and page_amount:
+                if count < page_num*page_amount and count >= (page_num-1)*page_amount :
+                    article_objs.append(article_tmp)
+                    count += 1
+                elif  count >= page_num*page_amount: count += 1
+                else : count += 1
+            else :
+                article_objs.append(article_tmp)
+                count += 1
+
+        return {"msg": "success", "code": 200, "total_num":count,"article": article_objs}
+    except Exception as e:
+        return {"msg": str(e), "code": 500}
+    

+ 158 - 43
app/api/classes.py

@@ -3,7 +3,7 @@ from typing import List,Optional
 from fastapi.responses import FileResponse
 from random import randint
 from fastapi.security import OAuth2PasswordRequestForm
-from app.models.models import User,Favorite_course
+from app.models.models import User,Favorite_course,Article_list
 from app.models.models import Class_list,Schools,Class_detail,Class_name,Registration,Group_name,Online_course
 from app.api import deps
 from sqlalchemy.orm import Session
@@ -23,7 +23,19 @@ import json
 
 classes = APIRouter()
 
-IMAGEDIR = "/var/www/html/ntcri/assets/"
+async def check_token(access_token: str):
+
+    result = await User.filter(token=access_token).first()
+    
+    if not result:
+        print("no access")
+        return None
+    
+    user_id = result.id
+
+    return user_id
+
+IMAGEDIR = "/var/www/ntcri/ntcri/assets/"
 IMAGEDIR_short = "assets/"
 
 async def update_location_time(location_id: int):
@@ -461,29 +473,33 @@ async def get_school_group():
 
 @classes.get("/get_class_name")
 async def get_class_name(
-    location_id : int = 0 ,
-    class_name_id : int = 0,
-    group_id : int = 0,
-    group_sort :str = None,
-    category :str = None
+    location_id : Optional[int] = None ,
+    class_name_id : Optional[int] = None,
+    group_id : Optional[int] = None,
+    group_sort :Optional[str] = None,
+    category :Optional[str] = None,
+    page_num : Optional[int] = None,
+    page_amount : Optional[int] = None
 ):
     try:
+        class_name_list = Class_name.all()
+
         if group_sort:
-            class_name_list = await Class_name.filter(group_sort = group_sort).all()
-        elif category:
-            class_name_list = await Class_name.filter(Q(category__icontains=category)).all()
-        elif location_id == 0:
-            if class_name_id == 0 :
-                class_name_list = await Class_name.all()
-            else :
-                class_name_list = await Class_name.filter(id = class_name_id).all()
-        else:
-            if class_name_id != 0 :
-                class_name_list = await Class_name.filter(school_id = location_id,id = class_name_id).all()
-            else:
-                class_name_list = await Class_name.filter(school_id = location_id).all()
+            class_name_list = class_name_list.filter(group_sort = group_sort).all()
+        
+        if category:
+            class_name_list = class_name_list.filter(Q(category__icontains=category)).all()
+        
+        if location_id :
+            class_name_list = class_name_list.filter(school_id = location_id).all()
+
+        if class_name_id :
+            class_name_list = class_name_list.filter(id = class_name_id).all()
 
+        class_name_list = await class_name_list.all()
         classes_name = []
+
+        count = 0
         for class_name_obj in class_name_list:
             school_obj = await Schools.filter(id=class_name_obj.school_id).all()
             school_name = ""
@@ -502,11 +518,19 @@ async def get_class_name(
                     "organizer": class_name_obj.organizer,
                     "group_id": class_name_obj.group_id,
                     "cover_img": class_name_obj.cover_img,
-                    "group_sort":group_sort
+                    "group_sort":class_name_obj.group_sort
                     }
-                classes_name.append(class_data)
-
-        return {"msg": "success", "code": 200, "classes": classes_name}
+                if page_num and page_amount:
+                    if count < page_num*page_amount and count >= (page_num-1)*page_amount :
+                        classes_name.append(class_data)
+                        count += 1
+                    elif  count >= page_num*page_amount: count += 1
+                    else : count += 1
+                else :
+                    classes_name.append(class_data)
+                    count += 1
+
+        return {"msg": "success", "code": 200,"total_num" : count,"classes": classes_name}
     
     except Exception as e:
         return {"msg": str(e), "code": 500}    
@@ -607,13 +631,15 @@ async def search_class_like(keyword: str):
 
 @classes.post("/add_favorite_class")
 async def add_favorite_class(
-        class_event_id: int, 
-        user_id : int,
+        class_name_id: int, 
+        user_id = Depends(check_token),
         time_stemp: datetime = datetime.now()
 ):
     try:
+        if not user_id:
+            return {"msg": "no access", "code": 500}
         new_favorite_class = await Favorite_course.get_or_create(
-            class_event_id=class_event_id,
+            class_name_id=class_name_id,
             user_id=user_id,
             defaults={'time_stemp': time_stemp}
         )
@@ -621,36 +647,49 @@ async def add_favorite_class(
     except Exception as e:
         return {"msg": str(e), "code": 500}
 
-@classes.get("get_favorite_class")
+@classes.get("/get_favorite_class")
 async def get_favorite_class( 
-        user_id : int
+        user_id = Depends(check_token),
+        no_details : Optional[int] = None
 ):
     try:
         class_list = await Favorite_course.filter(user_id = user_id).all()
         favorite_courses = []
         for class_obj in class_list:
-            class_event = await Class_list.get(id = class_obj.class_event_id)
-            class_name = await Class_name.get(id = class_event.name_id)
-            class_data = {
-                "id": class_obj.id,
-                "user_id": class_obj.user_id,
-                "class_event_id":class_obj.class_event_id,
-                "class_name_id" : class_name.id,
-                "time_stemp":class_obj.time_stemp
-            }
-            favorite_courses.append(class_data)
+            if no_details:
+                class_data = {
+                    "id": class_obj.id,
+                    "user_id": class_obj.user_id,
+                    "class_name_id" : class_obj.class_name_id,
+                    "time_stemp":class_obj.time_stemp
+                }
+                favorite_courses.append(class_data)
+            else:
+                class_data = {
+                    "id": class_obj.id,
+                    "user_id": class_obj.user_id,
+                    "class_name_id" : class_obj.class_name_id,
+                    "time_stemp":class_obj.time_stemp
 
-        return {"msg": "success", "code": 200, "school_groups": favorite_courses}
+                }
+
+                result = await get_class_name(class_name_id = class_obj.class_name_id)
+                class_detail = result["classes"][0]
+                for class_tmp in class_detail.items():
+                    class_data[class_tmp[0]] = class_tmp[1]
+                favorite_courses.append(class_data)        
+
+        return {"msg": "success", "code": 200, "favorite_courses": favorite_courses}
     except Exception as e:
         return {"msg": str(e), "code": 500}
 
 @classes.post("/delete_favorite_class")
 async def delete_favorite_class(
-        class_event_id: int, 
-        user_id : int
+        class_name_id: int, 
+        user_id = Depends(check_token)
 ):
     try:
-        await Favorite_course.filter(class_event_id=class_event_id,user_id=user_id).delete()
+        await Favorite_course.filter(class_name_id=class_name_id,user_id=user_id).delete()
         return {"msg": "success", "code": 200}
     except Exception as e:
         return {"msg": str(e), "code": 500}
@@ -747,3 +786,79 @@ async def delete_online_course(
     except Exception as e:
         return {"msg": str(e), "code": 500}
 
+@classes.get("/get_group_classes_and_articles")
+async def get_group_classes_and_articles(
+    group_id : int,
+    page_num : Optional[int] = None,
+    page_amount : Optional[int] = None
+):
+    try:
+        class_name_list = await Class_name.filter(group_id = group_id).all()
+        article_list = await Article_list.filter(group_id = group_id).all()
+
+        article_objs = []
+        article_count = 0
+        for article_obj in article_list:
+            article_tmp = {
+                "article_id": article_obj.id,
+                "title": article_obj.title,
+                "school_id" :article_obj.school_id,
+                "group_sort" :article_obj.group_sort,
+                "group_id" :article_obj.group_id,
+                "category": article_obj.category,
+                "create_time" : article_obj.create_time,
+                "click_time" : article_obj.click_time,
+                "depiction" : article_obj.depiction,
+                "content" : article_obj.content,
+                "files" : article_obj.files,
+                "vedio_url" : article_obj.vedio_url,
+                "tags" : article_obj.tags,
+                "cover_img": article_obj.cover_img
+            }
+            if page_num and page_amount:
+                if article_count < page_num*page_amount and article_count >= (page_num-1)*page_amount :
+                    article_objs.append(article_tmp)
+                    article_count += 1
+                elif  article_count >= page_num*page_amount: article_count += 1
+                else : article_count += 1
+            else :
+                article_objs.append(article_tmp)
+                article_count += 1
+
+        classes_name = []
+
+        class_count = 0
+        for class_name_obj in class_name_list:
+            school_obj = await Schools.filter(id=class_name_obj.school_id).all()
+            school_name = ""
+            if school_obj == []:
+                school_name = "未設定該據點"
+            else :
+                school_obj = await Schools.get(id=class_name_obj.school_id)
+                school_name = school_obj.name
+            if not group_id or class_name_obj.group_id==group_id:
+                class_data = {
+                    "class_name_id": class_name_obj.id,
+                    "name": class_name_obj.name,
+                    "school":school_name,
+                    "category": class_name_obj.category,
+                    "introduction": class_name_obj.introduction,
+                    "organizer": class_name_obj.organizer,
+                    "group_id": class_name_obj.group_id,
+                    "cover_img": class_name_obj.cover_img,
+                    "group_sort":class_name_obj.group_sort
+                    }
+                if page_num and page_amount:
+                    if class_count < page_num*page_amount and class_count >= (page_num-1)*page_amount :
+                        classes_name.append(class_data)
+                        class_count += 1
+                    elif  class_count >= page_num*page_amount: class_count += 1
+                    else : class_count += 1
+                else :
+                    classes_name.append(class_data)
+                    class_count += 1
+
+        return {"msg": "success", "code": 200,"class_num" : class_count,"classes": classes_name,"article_num":article_count,"articles": article_objs}
+    
+    except Exception as e:
+        return {"msg": str(e), "code": 500}    

+ 14 - 3
app/api/news.py

@@ -18,7 +18,7 @@ from fastapi.responses import HTMLResponse
 
 news = APIRouter()
 
-IMAGEDIR = "/var/www/html/ntcri/assets/news_files/"
+IMAGEDIR = "/var/www/ntcri/ntcri/assets/news_files/"
 IMAGEDIR_short = "assets/news_files/"
 
 @news.get("/get_news")
@@ -70,11 +70,21 @@ async def create_upload_files(files:Optional[List[UploadFile]] = File(None)):
 
     return files_url
 
+@news.post("/insert_news_imgs")
+async def insert_imgs(
+    files_url = Depends(create_upload_files)
+):
+    try:
+        files = str(files_url),
+        
+        return {"msg": "success", "code": 200, "url": files}
+    except Exception as e:
+        return {"msg": str(e), "code": 500}
+
 @news.post("/insert_news")
 async def insert_news(
     title : str = Form(default=''),
     category : str = Form(default=''),
-    create_time :str = Form(default=datetime.now()),
     content : str = Form(default=''),
     URL :str = Form(default=''),
     tags : str = Form(default='[]'),
@@ -95,7 +105,6 @@ async def insert_news(
         new_news = await News.create(
             title=title,
             category=category,
-            create_time=create_time,
             content=content,
             files = str(files_url),
             URL = URL,
@@ -197,4 +206,6 @@ async def search_class_like(keyword: str):
         return {"msg": "success", "code": 200, "news": news_objs}
     except Exception as e:
         return {"msg": str(e), "code": 500}
+    
+
     

+ 4 - 1
app/models/models.py

@@ -112,7 +112,7 @@ class News(Model):
 class Favorite_course(Model):
     id = fields.IntField(pk=True)
     user_id = fields.IntField(description="使用者ID")
-    class_event_id = fields.IntField(description="課程場次ID")
+    class_name_id = fields.IntField(description="課程ID")
     time_stemp = fields.DatetimeField(description="時間")
 
 class Article_list(Model):
@@ -120,6 +120,7 @@ class Article_list(Model):
     title = fields.CharField(max_length=45, description="標題")
     school_id = fields.IntField(description="學校ID")
     group_id = fields.IntField(description="學群")
+    group_sort = fields.CharField(max_length=45, description="學群細分")
     create_user_id = fields.IntField(description="創建使用者ID")
     create_time = fields.DatetimeField(description="創建時間")
     latest_update_user_id = fields.IntField(description="最新更新使用者ID")
@@ -132,6 +133,8 @@ class Article_list(Model):
     click_time = fields.IntField(description="點擊次數")
     content = fields.TextField(description="內容")
     is_del = fields.IntField(description="是否刪除")
+    files = fields.TextField(description="附件")
+    url = fields.TextField(description="文章連結")
 
 class Online_course(Model):
     id = fields.IntField(pk=True)