Skip to content

Commit f2f4a97

Browse files
author
yangjian
committed
新增注册邀请码功能,并优化部分样式
1 parent 3e8678e commit f2f4a97

17 files changed

Lines changed: 420 additions & 48 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ coverage.xml
5757
*.log
5858
local_settings.py
5959
db.sqlite3
60+
media
6061

6162
# Flask stuff:
6263
instance/

CHANGES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
## 版本更新记录
22

3+
### v0.2.10 2020-02-22
4+
5+
- 优化修改文档页面的文档状态提示;
6+
- 新增注册邀请码功能,可在后台配置管理;
7+
38
### v0.2.9 2020-02-17
49

510
- 优化文本编辑器排版

MrDoc/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
# SECURITY WARNING: don't run with debug turned on in production!
2626
DEBUG = False
2727

28-
VERSIONS = '0.2.9'
28+
VERSIONS = '0.2.10'
2929

3030
ALLOWED_HOSTS = ['*']
3131

README.md

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,46 @@
44

55
![Mrdoc首页](./docs/mrdoc_2019080101.gif)
66

7-
**手机端文档阅读界面:**
8-
9-
![移动端](./docs/mrdoc-2019-12-15_204807.jpg)
10-
117
## 介绍
12-
基于Python的一个简单文档写作系统。
138

14-
当前版本为:**v0.2.9**,版本发布时间为**2020-02-17**,更新记录详见:[CHANGES.md](./CHANGES.md)
9+
州的先生(zmister.com)自用并完全开源、基于Python编写的文档写作系统。
1510

11+
当前版本为:**v0.2.10**,版本发布时间为**2020-02-22**,更新记录详见:[CHANGES.md](./CHANGES.md)
1612

1713
MrDoc拥有以下特点:
1814

19-
- 基于Django自带的用户模型,实现简单高效的用户管理,支持用户注册、用户登录、管理员等控制等功能;
20-
- 基于Editormd的Markdown编辑器,支持Markdown语法的文档写作,支持图片粘贴上传;
21-
- 提供文档模板功能,支持文档模板的创建、修改;
22-
- 仿GitBook文档阅读页面,支持文档阅读页面的字体缩放,字体类型修改;
23-
- 支持三级目录层级显示;
24-
- 支持文集导出为markdown文本格式.md文件;
25-
- 支持基于文集的权限控制,提供公开、私密、指定用户可见、访问码可见4种权限模式;
26-
- 使用方便、二次开发修改也方便;
27-
28-
在开发过程中,参考和借鉴了GitBook、ShowDoc、Wordbook等应用的功能和样式。
29-
30-
## 软件架构
31-
32-
后端基于Python Web框架Django
33-
34-
编程语言:Python 3
35-
36-
后端框架:Django 2.1
37-
38-
前端UI库:LayUI 2.5.4
39-
40-
MarkDown编辑器:Editormd
41-
42-
页面社交分享:Share.js
43-
44-
Markdown科学公式:Katex.js
15+
- 站点与用户系统简洁
16+
- 基于Django自带的用户模型,实现简单高效的用户管理,支持用户注册、用户登录、管理员等控制等功能;
17+
- 支持全站关闭注册;
18+
- 支持注册邀请码配置;
19+
- 支持广告位自定义配置;
20+
- 支持统计代码自定义配置;
21+
22+
- 文档系统清晰
23+
- 基于文集的文档撰写和阅读;
24+
- 基于Editormd的Markdown编辑器,支持Markdown语法的文档写作,支持图片粘贴上传,支持从本地MD文件中插入内容;
25+
- 提供文档模板功能,支持文档模板的创建、修改;
26+
- 仿GitBook文档阅读页面,支持文档阅读页面的字体缩放,字体类型修改,页面社交分享,良好的移动端阅读体验;
27+
- 支持三级目录层级显示;
28+
- 支持文集导出为markdown文本格式.md文件;
29+
- 基于文集进行权限控制,提供公开、私密、指定用户可见、访问码可见4种权限模式;
30+
31+
- 二次开发方便
32+
- 使用Django传统的MTV开发模式,路由、视图函数、模型易于理解;
33+
- 使用非前端工程化构建前端页面,主要使用Layui进行页面布局和展示,方便改动;
34+
35+
36+
在开发过程中,参考和借鉴了GitBook、ShowDoc、Wordbook等应用和网站的功能与样式。
37+
38+
## 网站架构
39+
40+
- 编程语言:Python 3
41+
- 后端Web框架:Django 2.1
42+
- 前端UI库:Layui 2.5.4
43+
- JS库:Jquery
44+
- MarkDown编辑器:Editormd
45+
- 页面社交分享:Share.js
46+
- Markdown科学公式:Katex.js
4547

4648
## 安装教程
4749

@@ -51,7 +53,7 @@ pip install -r requirements.txt
5153
```
5254

5355
### 2、配置数据库信息
54-
默认情况下,MrDoc使用Django的SQLite数据库,如果你使用的是MrDoc源码附带的Sqlite数据库,则无需另外配置数据库。
56+
默认情况下,MrDoc使用Django的SQLite数据库,在旧版本MrDoc附带了一个Sqlit数据库,如果你使用的是MrDoc源码附带的Sqlite数据库,或使用Sqlite数据库,则无需另外配置数据库。
5557
如果有配置其他数据库的需求,请在/MrDoc/MrDoc目录下打开settings.py文件,在约80行的位置,将如下代码:
5658
```
5759
DATABASES = {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Generated by Django 2.1 on 2020-02-21 20:06
2+
3+
from django.conf import settings
4+
from django.db import migrations, models
5+
import django.db.models.deletion
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
12+
('app_admin', '0005_auto_20191125_2155'),
13+
]
14+
15+
operations = [
16+
migrations.CreateModel(
17+
name='RegisterCode',
18+
fields=[
19+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
20+
('code', models.CharField(max_length=10, unique=True, verbose_name='注册邀请码')),
21+
('all_cnt', models.IntegerField(default=1, verbose_name='有效注册数量')),
22+
('used_cnt', models.IntegerField(default=0, verbose_name='已使用数量')),
23+
('status', models.IntegerField(default=1, verbose_name='注册码状态')),
24+
('user_list', models.CharField(blank=True, max_length=500, null=True, verbose_name='使用此注册码的用户')),
25+
('create_time', models.DateTimeField(auto_now=True, verbose_name='创建时间')),
26+
('create_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
27+
],
28+
options={
29+
'verbose_name': '注册邀请码',
30+
'verbose_name_plural': '注册邀请码',
31+
},
32+
),
33+
]
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 2.1 on 2020-02-22 11:06
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('app_admin', '0006_registercode'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='registercode',
15+
name='user_list',
16+
field=models.CharField(blank=True, default='', max_length=500, null=True, verbose_name='使用此注册码的用户'),
17+
),
18+
]

app_admin/models.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
from django.db import models
2+
from django.contrib.auth.models import User
3+
24

35
# 系统设置项模型
46
class SysSetting(models.Model):
@@ -27,4 +29,24 @@ def __str__(self):
2729

2830
class Meta:
2931
verbose_name = '电子邮件验证码'
32+
verbose_name_plural = verbose_name
33+
34+
# 用户注册邀请码模型
35+
class RegisterCode(models.Model):
36+
code = models.CharField(verbose_name="注册邀请码",max_length=10,unique=True)
37+
# 注册码的有效注册数量,表示注册码最多能够被使用多少次,默认为1
38+
all_cnt = models.IntegerField(verbose_name="有效注册数量",default=1)
39+
# 注册码的已使用数量,其值小于等于有效注册数量,默认为0
40+
used_cnt = models.IntegerField(verbose_name='已使用数量',default=0)
41+
# 注册码状态:0表示数据已满,1表示有效,默认为1
42+
status = models.IntegerField(verbose_name="注册码状态",default=1)
43+
user_list = models.CharField(verbose_name="使用此注册码的用户",default='',max_length=500,blank=True,null=True)
44+
create_user = models.ForeignKey(User,on_delete=models.CASCADE)
45+
create_time = models.DateTimeField(auto_now=True,verbose_name='创建时间')
46+
47+
def __str__(self):
48+
return self.code
49+
50+
class Meta:
51+
verbose_name = '注册邀请码'
3052
verbose_name_plural = verbose_name

app_admin/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@
1818
path('check_code/',views.check_code,name='check_code'), # 注册验证码
1919
path('forget_pwd/',views.forget_pwd,name='forget_pwd'), # 忘记密码
2020
path('send_email_vcode/',views.send_email_vcode,name='send_email_vcode'), # 忘记密码发送邮件验证码
21+
path('admin_register_code/',views.admin_register_code,name='register_code_manage'), # 注册邀请码管理
2122

2223
]

app_admin/views.py

Lines changed: 99 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
from django.contrib.auth.decorators import login_required # 登录需求装饰器
77
from django.core.paginator import Paginator,PageNotAnInteger,EmptyPage,InvalidPage # 后端分页
88
from app_admin.decorators import superuser_only,open_register
9-
import json,datetime,hashlib
9+
from django.core.exceptions import ObjectDoesNotExist
10+
import json,datetime,hashlib,random
1011
from app_doc.models import *
1112
from app_admin.models import *
1213
from app_admin.utils import *
@@ -68,20 +69,29 @@ def register(request):
6869
email = request.POST.get('email',None)
6970
password = request.POST.get('password',None)
7071
checkcode = request.POST.get("check_code",None)
72+
register_code = request.POST.get("register_code",None)
73+
is_register_code = SysSetting.objects.filter(types='basic', name='enable_register_code', value='on')
74+
if is_register_code.count() > 0: # 开启了注册码设置
75+
try:
76+
register_code_value = RegisterCode.objects.get(code=register_code,status=1)
77+
except ObjectDoesNotExist:
78+
errormsg = '注册码无效!'
79+
return render(request, 'register.html', locals())
80+
# 判断是否输入了用户名、邮箱和密码
7181
if username and email and password:
7282
if '@'in email:
7383
email_exit = User.objects.filter(email=email)
7484
username_exit = User.objects.filter(username=username)
75-
if email_exit.count() > 0:
85+
if email_exit.count() > 0: # 验证电子邮箱
7686
errormsg = '此电子邮箱已被注册!'
7787
return render(request, 'register.html', locals())
78-
elif username_exit.count() > 0:
88+
elif username_exit.count() > 0: # 验证用户名
7989
errormsg = '用户名已被使用!'
8090
return render(request, 'register.html', locals())
81-
elif len(password) < 6:
91+
elif len(password) < 6: # 验证密码长度
8292
errormsg = '密码必须大于等于6位!'
8393
return render(request, 'register.html', locals())
84-
elif checkcode != request.session['CheckCode'].lower():
94+
elif checkcode != request.session['CheckCode'].lower(): # 验证验证码
8595
errormsg = "验证码错误"
8696
return render(request, 'register.html', locals())
8797
else:
@@ -90,11 +100,27 @@ def register(request):
90100
user.save()
91101
# 登录用户
92102
user = authenticate(username=username, password=password)
103+
# 注册码数据更新
104+
if is_register_code.count() > 0:
105+
r_all_cnt = register_code_value.all_cnt # 注册码的最大使用次数
106+
r_used_cnt = register_code_value.used_cnt + 1 # 更新注册码的已使用次数
107+
r_use_user = register_code_value.user_list # 注册码的使用用户
108+
if r_used_cnt >= r_all_cnt: # 如果注册码已使用次数大于等于注册码的最大使用次数,则注册码失效
109+
RegisterCode.objects.filter(code=register_code).update(
110+
status=0,# 注册码状态设为失效
111+
used_cnt = r_used_cnt, # 更新注册码的已使用次数
112+
user_list = r_use_user + email + ',',
113+
)
114+
else:
115+
RegisterCode.objects.filter(code=register_code).update(
116+
used_cnt=r_used_cnt, # 更新注册码的已使用次数
117+
user_list = r_use_user + email + ',',
118+
)
93119
if user.is_active:
94120
login(request, user)
95121
return redirect('/')
96122
else:
97-
errormsg = '用户被禁用!'
123+
errormsg = '用户被禁用,请联系管理员!'
98124
return render(request, 'register.html', locals())
99125
else:
100126
errormsg = '请输入正确的电子邮箱格式!'
@@ -388,6 +414,62 @@ def admin_doctemp(request):
388414
return render(request,'app_admin/admin_doctemp.html',locals())
389415

390416

417+
# 管理员后台 - 注册邀请码管理
418+
@superuser_only
419+
def admin_register_code(request):
420+
# 返回注册邀请码管理页面
421+
if request.method == 'GET':
422+
register_codes = RegisterCode.objects.all()
423+
paginator = Paginator(register_codes, 10)
424+
page = request.GET.get('page', 1)
425+
try:
426+
codes = paginator.page(page)
427+
except PageNotAnInteger:
428+
codes = paginator.page(1)
429+
except EmptyPage:
430+
codes = paginator.page(paginator.num_pages)
431+
return render(request,'app_admin/admin_register_code.html',locals())
432+
elif request.method == 'POST':
433+
types = request.POST.get('types',None)
434+
if types is None:
435+
return JsonResponse({'status':False,'data':'参数错误'})
436+
# types表示注册码操作的类型,1表示新增、2表示删除
437+
if int(types) == 1:
438+
try:
439+
all_cnt = int(request.POST.get('all_cnt',1)) # 注册码的最大使用次数
440+
is_code = False
441+
while is_code is False:
442+
code_str = '0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM'
443+
random_code = ''.join(random.choices(code_str, k=10))
444+
random_code_used = RegisterCode.objects.filter(code=random_code).count()
445+
if random_code_used > 0: # 已存在此注册码,继续生成一个注册码
446+
is_code = False
447+
else:# 数据库中不存在此注册码,跳出循环
448+
is_code = True
449+
# 创建一个注册码
450+
RegisterCode.objects.create(
451+
code = random_code,
452+
all_cnt = all_cnt,
453+
create_user = request.user
454+
)
455+
return JsonResponse({'status':True,'data':'新增成功'})
456+
except Exception as e:
457+
return JsonResponse({'status': False,'data':'系统异常'})
458+
elif int(types) == 2:
459+
code_id = request.POST.get('code_id',None)
460+
try:
461+
register_code = RegisterCode.objects.get(id=int(code_id))
462+
register_code.delete()
463+
return JsonResponse({'status':True,'data':'删除成功'})
464+
except ObjectDoesNotExist:
465+
return JsonResponse({'status':False,'data':'注册码不存在'})
466+
except:
467+
return JsonResponse({'status':False,'data':'系统异常'})
468+
else:
469+
return JsonResponse({'status':False,'data':'类型错误'})
470+
else:
471+
return JsonResponse({'status': False,'data':'方法错误'})
472+
391473
# 普通用户修改密码
392474
@login_required()
393475
def change_pwd(request):
@@ -429,11 +511,12 @@ def admin_setting(request):
429511
types = request.POST.get('type',None)
430512
# 基础设置
431513
if types == 'basic':
432-
close_register = request.POST.get('close_register',None)
433-
static_code = request.POST.get('static_code',None)
434-
ad_code = request.POST.get('ad_code',None)
435-
beian_code = request.POST.get('beian_code',None)
436-
enbale_email = request.POST.get("enable_email",None)
514+
close_register = request.POST.get('close_register',None) # 禁止注册
515+
static_code = request.POST.get('static_code',None) # 统计代码
516+
ad_code = request.POST.get('ad_code',None) # 广告代码
517+
beian_code = request.POST.get('beian_code',None) # 备案号
518+
enbale_email = request.POST.get("enable_email",None) # 启用邮箱
519+
enable_register_code = request.POST.get('enable_register_code',None) # 注册邀请码
437520
# 更新开放注册状态
438521
SysSetting.objects.update_or_create(
439522
name='close_register',
@@ -459,6 +542,11 @@ def admin_setting(request):
459542
name='enable_email',
460543
defaults={'value': enbale_email, 'types': 'basic'}
461544
)
545+
# 更新注册码启停状态
546+
SysSetting.objects.update_or_create(
547+
name = 'enable_register_code',
548+
defaults= {'value': enable_register_code, 'types':'basic'}
549+
)
462550

463551
return render(request,'app_admin/admin_setting.html',locals())
464552
elif types == 'email':

app_doc/views.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,11 @@ def manage_doc(request):
398398
docs.kw = search_kw
399399
else:
400400
doc_list = Doc.objects.filter(create_user=request.user).order_by('-modify_time')
401+
all_cnt = doc_list.count() # 所有文档数量
402+
published_doc_cnt = Doc.objects.filter(create_user=request.user,status=1).count() # 已发布文档数量
403+
draft_doc_cnt = Doc.objects.filter(create_user=request.user,status=0).count() # 草稿文档数据
404+
pro_list = Project.objects.filter(create_user=request.user)
405+
401406
paginator = Paginator(doc_list, 10)
402407
page = request.GET.get('page', 1)
403408
try:

0 commit comments

Comments
 (0)