Browse Source

数据库

zoe 4 years ago
parent
commit
f9b26837dd

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml

+ 22 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -0,0 +1,22 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
+      <option name="ignoredErrors">
+        <list>
+          <option value="N801" />
+          <option value="N806" />
+          <option value="N802" />
+        </list>
+      </option>
+    </inspection_tool>
+    <inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
+      <option name="ignoredIdentifiers">
+        <list>
+          <option value="chat.models.message.objects" />
+          <option value="chat.models.message.DoesNotExist" />
+        </list>
+      </option>
+    </inspection_tool>
+  </profile>
+</component>

+ 6 - 0
.idea/inspectionProfiles/profiles_settings.xml

@@ -0,0 +1,6 @@
+<component name="InspectionProjectProfileManager">
+  <settings>
+    <option name="USE_PROJECT_PROFILE" value="false" />
+    <version value="1.0" />
+  </settings>
+</component>

+ 4 - 0
.idea/misc.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (hy_env)" project-jdk-type="Python SDK" />
+</project>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/st_cloud.iml" filepath="$PROJECT_DIR$/.idea/st_cloud.iml" />
+    </modules>
+  </component>
+</project>

+ 28 - 0
.idea/st_cloud.iml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="PYTHON_MODULE" version="4">
+  <component name="FacetManager">
+    <facet type="django" name="Django">
+      <configuration>
+        <option name="rootFolder" value="$MODULE_DIR$" />
+        <option name="settingsModule" value="st_cloud/settings.py" />
+        <option name="manageScript" value="$MODULE_DIR$/manage.py" />
+        <option name="environment" value="&lt;map/&gt;" />
+        <option name="doNotUseTestRunner" value="false" />
+        <option name="trackFilePattern" value="migrations" />
+      </configuration>
+    </facet>
+  </component>
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+  <component name="TemplatesService">
+    <option name="TEMPLATE_CONFIGURATION" value="Django" />
+    <option name="TEMPLATE_FOLDERS">
+      <list>
+        <option value="$MODULE_DIR$/../st_cloud\templates" />
+      </list>
+    </option>
+  </component>
+</module>

+ 7 - 0
.idea/vcs.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+    <mapping directory="$PROJECT_DIR$/libgit2" vcs="Git" />
+  </component>
+</project>

+ 0 - 0
account/__init__.py


+ 3 - 0
account/admin.py

@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.

+ 6 - 0
account/apps.py

@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class AccountConfig(AppConfig):
+    default_auto_field = 'django.db.models.BigAutoField'
+    name = 'account'

+ 28 - 0
account/form.py

@@ -0,0 +1,28 @@
+from django import forms
+from django.contrib.auth.models import User
+from .models import Profile
+
+
+class UserLoginForm(forms.Form):
+    username = forms.CharField()
+    password = forms.CharField()
+    token = forms.CharField()
+
+
+class UserRegisterForm(forms.ModelForm):
+    password = forms.CharField()
+    password2 = forms.CharField()
+
+    class Meta:
+        model = User
+        fields = ('username', 'email')
+
+    def clean_password2(self):
+        data = self.cleaned_data
+        if data.get('password') == data.get('password2'):
+            return data.get('password')
+        else:
+            raise forms.ValidationError('密码输入不一致,请重新输入!')
+
+
+

+ 0 - 0
account/migrations/__init__.py


+ 55 - 0
account/models.py

@@ -0,0 +1,55 @@
+import hashlib
+import datetime
+
+from django.db import models
+from folder.models import Folder
+from django.contrib.auth.models import User
+# 引入内置信号
+from django.db.models.signals import post_save
+# 引入信号接收器的装饰器
+from django.dispatch import receiver
+
+
+# Create your views here.
+class Profile(models.Model):
+    # 对应django自带的user
+    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
+    # 邮箱
+    email = models.CharField(max_length=20, blank=True)
+    # 密码
+    password = models.CharField(max_length=500, blank=True)
+    # 对应的根目录
+    root_folder = models.OneToOneField(Folder, on_delete=models.CASCADE, related_name='root_folder')
+
+    def __str__(self):
+        return 'user {}'.format(self.user.username)
+
+
+class Devices(models.Model):
+    # 对应django自带的User
+    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='devices')
+    # 设备登录时间
+    last_login_time = models.DateField(auto_now=True)
+    # 设备码
+    device_uid = models.CharField(max_length=100, default='233', blank=False, unique=True)
+    # 登录凭证
+    token = models.CharField(max_length=100, default='233', blank=False, unique=True)
+
+    def gen_token(self):
+        _token = self.device_uid + self.user.username + datetime.datetime.now().strftime("%Y%m%d%H%M%S")
+        sha1 = hashlib.sha1()
+        sha1.update(_token.encode())
+        self.token = sha1.hexdigest()
+
+
+# 信号接收函数,每当新建User实例的时候自动调用
+@receiver(post_save, sender=User)
+def create_user_profile(sender, instance, created, **kwargs):
+    if created:
+        Profile.objects.create(user=instance)
+
+
+# 信号接收函数,每当更新User实例的时候自动调用
+@receiver(post_save, sender=User)
+def save_user_profile(sender, instance, **kwargs):
+    instance.profile.save()

+ 25 - 0
account/templates/login.html

@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html lang="zh-cn">
+    <div>
+        <form method="post" action=".">
+            {% csrf_token %}
+            <!-- 账号 -->
+            <div>
+                <label for="username">账号</label>
+                <input type="text" id="username" name="username">
+            </div>
+            <!-- 密码 -->
+            <div>
+                <label for="password">密码</label>
+                <input type="password" id="password" name="password">
+            </div>
+            <!-- new_token -->
+            <div>
+                <label for="token">新token</label>
+                <input type="text" id="token" name="token">
+            </div>
+            <!-- 提交按钮 -->
+            <button type="submit">提交</button>
+        </form>
+    </div>
+</html>

+ 30 - 0
account/templates/register.html

@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html lang="zh-cn">
+    <div>
+        <form method="post" action=".">
+            {% csrf_token %}
+            <!-- 昵称 -->
+            <div>
+                <label for="username">昵称</label>
+                <input type="text" id="username" name="username">
+            </div>
+            <!-- 邮箱 -->
+            <div>
+                <label for="email">邮箱</label>
+                <input type="text" id="email" name="email">
+            </div>
+            <!-- 密码 -->
+            <div>
+                <label for="password">设置密码</label>
+                <input type="password" id="password" name="password" required>
+            </div>
+            <!-- 确认密码 -->
+            <div>
+                <label for="password2">确认密码</label>
+                <input type="password" id="password2" name="password2" required>
+            </div>
+            <!-- 提交按钮 -->
+            <button type="submit">提交</button>
+        </form>
+    </div>
+</html>

+ 3 - 0
account/tests.py

@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.

+ 9 - 0
account/urls.py

@@ -0,0 +1,9 @@
+from django.shortcuts import render
+from django.urls import path
+from . import views
+# Create your views here.
+urlpatterns = [
+    path('login/', views.user_login, name='login'),
+    path('logout/', views.user_logout, name='logout'),
+    path('register/', views.user_register, name='register'),
+]

+ 126 - 0
account/views.py

@@ -0,0 +1,126 @@
+from django.shortcuts import render
+from .form import UserLoginForm, UserRegisterForm
+from django.contrib.auth import authenticate, login, logout
+from django.http import HttpResponse
+from .models import Devices
+
+import random
+import datetime
+import json
+
+"""
+在此处修改token过期时间,30代表30天过期
+"""
+expiration_date = 30
+DEBUG = True
+
+
+def user_login(request):
+    if request.method == 'POST':
+        data = request.POST
+        # 检测是否有登录凭证
+        if data['token'] != 'token':
+            try:
+                device = Devices.objects.filter(token__exact=data['token']).get()
+                sub_time = (device.last_login_time - datetime.date.today()).total_seconds() / (3600 * 24)
+                # 检查token是否过期
+                if sub_time < expiration_date:
+                    # 更新此user此设备的token
+                    # token由设备uid、用户名、当前时间hash得来
+                    device.gen_token()
+                    device.save()
+                    # 登录
+                    user = device.user
+                    login(request, user)
+                    response = {'token': device.token}
+                    return HttpResponse(json.dumps(response), status=200)
+                    # return redirect("chat:index")
+                else:
+                    return HttpResponse(status=420)
+            # 已过期的token并且已经被删除
+            except Devices.DoesNotExist:
+                return HttpResponse(status=420)
+        else:
+            # 检测账号密码是否匹配数据库中的一个用户
+            # 如果均匹配,则返回此User对象
+            user = authenticate(username=data['username'], password=data['password'])
+            if user:
+                if data['token'] == 'token':
+                    # 新建一个该user的设备
+                    device = create_new_device(user)
+                else:
+                    # 此时,客户端带来了过期的旧token,现在需要更新旧的token
+                    try:
+                        device = Devices.objects.filter(token__exact=data['token']).get()
+                        device.gen_token()
+                        device.save()
+                    except Devices.DoesNotExist:
+                        # 新建一个该user的设备
+                        device = create_new_device(user)
+                login(request, user)
+                response = {'token': device.token}
+                return HttpResponse(json.dumps(response), status=200)
+            else:
+                return HttpResponse(status=401)
+    # 用于测试,登录界面
+    elif request.method == 'GET':
+        if DEBUG:
+            user_login_form = UserLoginForm()
+            context = {'form': user_login_form}
+            return render(request, 'login.html', context)
+    else:
+        # 请求方法错误,请使用POST
+        return HttpResponse(status=400)
+
+
+# 新建一个该user的设备
+def create_new_device(user):
+    device = Devices()
+    device.user = user
+    device.device_uid = generate_random_str(100)
+    device.gen_token()
+    device.save()
+    return device
+
+
+def generate_random_str(random_length=16):
+    """
+    生成一个指定长度的随机字符串
+    """
+    random_str = ''
+    base_str = 'ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789'
+    length = len(base_str) - 1
+    for i in range(random_length):
+        random_str += base_str[random.randint(0, length)]
+    return random_str
+
+
+def user_logout(request):
+    logout(request)
+    return HttpResponse(status=200)
+
+
+def user_register(request):
+    if request.method == 'POST':
+        user_register_form = UserRegisterForm(data=request.POST)
+        if user_register_form.is_valid():
+            # 新建一个user,但是不提交
+            new_user = user_register_form.save(commit=False)
+            # 设置密码
+            new_user.set_password(user_register_form.cleaned_data['password'])
+            # 保存
+            new_user.save()
+            return HttpResponse(status=200)
+        else:
+            return HttpResponse(status=400)
+    # 用于测试
+    elif request.method == 'GET':
+        if DEBUG:
+            user_register_form = UserRegisterForm()
+            context = {'form': user_register_form}
+            return render(request, 'register.html', context)
+    else:
+        return HttpResponse(status=400)
+
+
+

BIN
db.sqlite3


+ 0 - 0
file/__init__.py


+ 3 - 0
file/admin.py

@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.

+ 6 - 0
file/apps.py

@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class FileConfig(AppConfig):
+    default_auto_field = 'django.db.models.BigAutoField'
+    name = 'file'

+ 0 - 0
file/migrations/__init__.py


+ 13 - 0
file/models.py

@@ -0,0 +1,13 @@
+from django.db import models
+from folder.models import Folder
+
+
+# 文件表
+class File(models.Model):
+    # 文件id
+    file_id = models.AutoField(primary_key=True)
+    # 文件名
+    file_name = models.CharField(max_length=50, blank=False)
+    # 从属的文件夹
+    folder = models.ForeignKey(Folder, on_delete=models.CASCADE, related_name='file_folder')
+    # file存储 置空

+ 3 - 0
file/tests.py

@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.

+ 3 - 0
file/views.py

@@ -0,0 +1,3 @@
+from django.shortcuts import render
+
+# Create your views here.

+ 0 - 0
folder/__init__.py


+ 3 - 0
folder/admin.py

@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.

+ 6 - 0
folder/apps.py

@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class FolderConfig(AppConfig):
+    default_auto_field = 'django.db.models.BigAutoField'
+    name = 'folder'

+ 0 - 0
folder/migrations/__init__.py


+ 14 - 0
folder/models.py

@@ -0,0 +1,14 @@
+from django.db import models
+
+
+# 文件夹表
+class Folder(models.Model):
+    # 文件夹id
+    folder_id = models.AutoField(primary_key=True)
+    # 文件夹名
+    folder_name = models.CharField(max_length=50, blank=False)
+    # 父节点
+    father_folder = models.ForeignKey('self', blank=True, on_delete=models.CASCADE, related_name='father_folder')
+
+    def __unicode__(self):
+        return self.folder_id

+ 3 - 0
folder/tests.py

@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.

+ 3 - 0
folder/views.py

@@ -0,0 +1,3 @@
+from django.shortcuts import render
+
+# Create your views here.

+ 0 - 0
group/__init__.py


+ 3 - 0
group/admin.py

@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.

+ 6 - 0
group/apps.py

@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class GroupConfig(AppConfig):
+    default_auto_field = 'django.db.models.BigAutoField'
+    name = 'group'

+ 0 - 0
group/migrations/__init__.py


+ 18 - 0
group/models.py

@@ -0,0 +1,18 @@
+from django.db import models
+from folder.models import Folder
+from django.contrib.auth.models import User
+
+
+# 群表
+class Group(models.Model):
+    # 群id
+    group_id = models.AutoField(primary_key=True)
+    # 群名
+    group_name = models.CharField(max_length=50, blank=False)
+    # 群管理员
+    creator = models.CharField(max_length=50, blank=False)
+    # 群文件夹
+    folder = models.ForeignKey(Folder, on_delete=models.CASCADE, related_name='group_folder')
+    # 群成员(多对多)
+    member = models.ManyToManyField(User)
+

+ 3 - 0
group/tests.py

@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.

+ 4 - 0
group/views.py

@@ -0,0 +1,4 @@
+from django.shortcuts import render
+
+# Create your views here.
+#

+ 22 - 0
manage.py

@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+"""Django's command-line utility for administrative tasks."""
+import os
+import sys
+
+
+def main():
+    """Run administrative tasks."""
+    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'st_cloud.settings')
+    try:
+        from django.core.management import execute_from_command_line
+    except ImportError as exc:
+        raise ImportError(
+            "Couldn't import Django. Are you sure it's installed and "
+            "available on your PYTHONPATH environment variable? Did you "
+            "forget to activate a virtual environment?"
+        ) from exc
+    execute_from_command_line(sys.argv)
+
+
+if __name__ == '__main__':
+    main()

+ 0 - 0
st_cloud/__init__.py


+ 16 - 0
st_cloud/asgi.py

@@ -0,0 +1,16 @@
+"""
+ASGI config for st_cloud project.
+
+It exposes the ASGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
+"""
+
+import os
+
+from django.core.asgi import get_asgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'st_cloud.settings')
+
+application = get_asgi_application()

+ 136 - 0
st_cloud/settings.py

@@ -0,0 +1,136 @@
+"""
+Django settings for st_cloud project.
+
+Generated by 'django-admin startproject' using Django 3.2.7.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/3.2/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/3.2/ref/settings/
+"""
+
+from pathlib import Path
+
+# Build paths inside the project like this: BASE_DIR / 'subdir'.
+BASE_DIR = Path(__file__).resolve().parent.parent
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = 'django-insecure-h1r^p(6-s&@7u!q(sv%_@97fxv(ikbi7d9p#i9+-o_3&pbpw(j'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# Application definition
+
+INSTALLED_APPS = [
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'api.apps.ApiConfig',
+    'rest_framework',
+]
+
+# 设置权限策略:
+REST_FRAMEWORK = {
+    'DEFAULT_PERMISSION_CLASSES': [
+        'rest_framework.permissions.IsAdminUser',
+    ],
+    'PAGE_SIZE': 10
+}
+
+MIDDLEWARE = [
+    'django.middleware.security.SecurityMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'st_cloud.urls'
+
+TEMPLATES = [
+    {
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        'DIRS': [BASE_DIR / 'templates']
+        ,
+        'APP_DIRS': True,
+        'OPTIONS': {
+            'context_processors': [
+                'django.template.context_processors.debug',
+                'django.template.context_processors.request',
+                'django.contrib.auth.context_processors.auth',
+                'django.contrib.messages.context_processors.messages',
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = 'st_cloud.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': BASE_DIR / 'db.sqlite3',
+    }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+    {
+        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+    },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/3.2/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/3.2/howto/static-files/
+
+STATIC_URL = '/static/'
+
+# Default primary key field type
+# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
+
+DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

+ 21 - 0
st_cloud/urls.py

@@ -0,0 +1,21 @@
+"""st_cloud URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+    https://docs.djangoproject.com/en/3.2/topics/http/urls/
+Examples:
+Function views
+    1. Add an import:  from my_app import views
+    2. Add a URL to urlpatterns:  path('', views.home, name='home')
+Class-based views
+    1. Add an import:  from other_app.views import Home
+    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
+Including another URLconf
+    1. Import the include() function: from django.urls import include, path
+    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
+"""
+from django.contrib import admin
+from django.urls import path
+
+urlpatterns = [
+    path('admin/', admin.site.urls),
+]

+ 16 - 0
st_cloud/wsgi.py

@@ -0,0 +1,16 @@
+"""
+WSGI config for st_cloud project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'st_cloud.settings')
+
+application = get_wsgi_application()