Tornado笔记——用Tornado搭建假单统计考勤系统(七)

在上一篇博客中,我们对项目结构进行了一些调整,并且实现了查看考勤功能。今天我们来补全一些用户系统的功能:用户管理、批准用户、注销用户、用户登出这4个功能。

9 用户管理、批准、注销及登出

此功能的作用是批准用户的注册,并同时调整其用户组。只有得到了批准的用户在之后的权限系统中才能使用相关功能。该功能的页面如下:

在这个页面,我们可以看到所有的用户(除了Root用户外),也会显示出每个用户的邮箱、所属用户组、状态、注册时间和最后登录时间。在每行的最后,可以对用户进行注销或批准的操作。从图上可知,test用户和test1用户已经被批准,状态为Approved,最后的操作栏显示为注销;test2用户被注销,状态为Logoff;而test3用户为待批准状态,所以其最后的操作按钮显示批准。 用户组的下拉框将列出除Root和Visitor之外的所有用户组。

我们打开user_app.py,来实现UserManage的get请求:

# util/users/userutil.py
def getallusergroup():
    usergroup = session.query(UserGroup).filter(and_(UserGroup.groupname != 'Root',UserGroup.groupname != 'Visitor'))
    return usergroup


# user_app.py
class UserManage(BaseHandler):
    def get(self):
        usermanagepath = gettemplatepath('usermanage.html')
        users = session.query(User).filter(User.username != 'Root')
        usergroups = getallusergroup()
        userInfos = []
        for user in users:
            userInfo = {}
            usergrouplist = []
            userInfo['username'] = user.username
            userInfo['email'] = user.email
            userInfo['usergroup'] = user.usergroup
            if user.usergroup not in usergrouplist:
                usergrouplist.append(user.usergroup)
            userInfo['state'] = user.state
            userInfo['registerdate'] = user.registerdate
            userInfo['lastlogintime'] = user.lastlogintime
            if user.state == 'Approved':
                userInfo['submit'] = '/logoff'
            else:
                userInfo['submit'] = '/approve'
            userInfo['formid'] = user.id
            userInfo['groupid'] = str(user.id)+'_group'
            for othergroup in usergroups:
                if othergroup.groupname not in usergrouplist:
                    usergrouplist.append(othergroup.groupname)
            userInfo['usergrouplist'] = usergrouplist
            userInfos.append(userInfo)

        self.render(usermanagepath,userInfos=userInfos,usergroups=usergrouplist)

# main.py
routelist = [
    # ...
    (r"/usermanage",UserManage),
    # ...
]

在UserManage这个RequestHandler中,只包含一个get方法,它会把每个用户的相关信息组成字典,存入userInfos这个list中。值得注意的是formid和groupid这两个值,由于我们在一个页面上有多个表单,因此需要构造formid和groupid来区分每个表单,否则在获取表单值的时候会取错数据;此外,我们还要根据用户状态的不同来决定submit所对应的url是批准还是注销。

前端usermanage.html的代码如下:

<!--usermanage.html-->
        {% block content %}
        <div class="page-wrapper">
            <!-- ============================================================== -->
            <!-- Container fluid  -->
            <!-- ============================================================== -->
            <div class="container-fluid">
                <!-- ============================================================== -->
                <!-- Bread crumb and right sidebar toggle -->
                <!-- ============================================================== -->
                <div class="row page-titles">
                    <div class="col-md-6 col-8 align-self-center">
                        <h3 class="text-themecolor m-b-0 m-t-0">用户审批</h3>
                        <ol class="breadcrumb">
                            <li class="breadcrumb-item"><a href="/">Home</a></li>
                            <li class="breadcrumb-item active">用户审批</li>
                        </ol>
                    </div>
                </div>
                <!-- ============================================================== -->
                <!-- End Bread crumb and right sidebar toggle -->
                <!-- ============================================================== -->
                <!-- ============================================================== -->
                <!-- Start Page Content -->
                <!-- ============================================================== -->
                <div class="row">
                    <!-- column -->
                    <div class="col-sm-12">
                        <div class="card">
                            <div class="card-block">
                                <h4 class="card-title">用户审批</h4>
                                <div class="table-responsive">
                                    <table class="table">
                                        <thead>
                                            <tr>
                                                <th>#</th>
                                                <th>用户名</th>
                                                <th>邮箱</th>
                                                <th>用户组</th>
                                                <th>状态</th>
                                                <th>注册时间</th>
                                                <th>最后登录时间</th>
                                                <th>操作</th>
                                            </tr>
                                        </thead>
                                        <tbody>
                                            {% for userinfo in userInfos %}
                                            <tr>
                                                <form method="post" id="{{ userinfo['formid'] }}" action="{{ escape(userinfo['submit']) }}">
                                                    <td><input type="text" value="{{ userinfo['formid'] }}" readonly=true id='userid' name='userid'/></td>
                                                    <td><input type="text" value="{{ escape(userinfo['username']) }}" readonly=true id='username' name='username'/></td>
                                                    <td>{{ escape(userinfo['email']) }}</td>
                                                    <td><select class="form-control form-control-line" name="{{ escape(userinfo['groupid']) }}" id="{{ escape(userinfo['groupid']) }}" >
                                                        {% for usergroup in userinfo['usergrouplist'] %}
                                                            <option>{{ escape(usergroup) }}</option>
                                                        {% end %}
                                                        </select>
                                                    </td>
                                                    <td>{{ escape(userinfo['state']) }}</td>
                                                    <td>{{ userinfo['registerdate'] }}</td>
                                                    <td>{{ userinfo['lastlogintime'] }}</td>
                                                    {% if escape(userinfo['state']) == 'Approved' %}
                                                    <td><button type="submit" class="btn btn-danger">注销</button></td>
                                                    {% else %}
                                                    <td><button type="submit" class="btn btn-success">批准</button></td>
                                                    {% end %}
                                                </form>
                                            </tr>
                                            {% end %}
                                        </tbody>
                                    </table>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <!-- ============================================================== -->
                <!-- End PAge Content -->
                <!-- ============================================================== -->
            </div>
            <!-- ============================================================== -->
            <!-- End Container fluid  -->
            <!-- ============================================================== -->
            <!-- ============================================================== -->
            <!-- footer -->
            <!-- ============================================================== -->
            <footer class="footer text-center">
                © 2020 Tornado考勤系统
            </footer>
            <!-- ============================================================== -->
            <!-- End footer -->
            <!-- ============================================================== -->
        </div>
        {% end %}

这里我们遍历userInfos这个list,为每个用户建立一个表单,注意我们的表单的action值也是从userInfo里获得的,对应批准或注销操作。

我们来看要如何批准或注销一个用户。批准用户或注销用户其实很简单,就是将用户的state字段的值改为Approved或Logoff;此外,我们还希望当用户得到批准时,向用户的邮箱发送一封email来提示用户,因此我们需要实现一个email模块。

我们在util包下建立email包,再在其中建立emailutil.py,开始实现发送email的功能:

from email.header import Header
from email.mime.text import MIMEText
import smtplib
from setting.globalsettings import getconfig


class Email():
    def __init__(self,toaddr):
        self.__smtpserver = getconfig('SMTPSERVER')
        self.__fromaddr = getconfig('EMAIL')
        self.__toaddr = toaddr
        self.__password = 'ilegxhawxgchbfcc'


    def sendemail(self,subject,content):
        msg = MIMEText(content,'html','utf-8')
        msg['From'] = self.__fromaddr
        msg['To'] = self.__toaddr
        subject = '[Tornado考勤系统] ' + subject
        msg['Subject'] = Header(subject,'utf-8').encode()
        server = smtplib.SMTP(self.__smtpserver, 25)
        server.login(self.__fromaddr, self.__password)
        try:
            server.sendmail(self.__fromaddr, [self.__toaddr], msg.as_string())
        except Exception as e:
            print(e)
        finally:
            server.quit()


def sendapprovemail(username,usergroup,email):
    approvemail = Email(email)
    subject = '[Tornado考勤系统] 用户批准'
    content = '''
    <html>
    <body>
    <p>Dear %s:</p>
    <p>您的注册已被批准,用户组为%s</p>
    </body>
    </html>
    ''' % (username,usergroup)
    approvemail.sendemail(subject,content)

由于我没有outlook,因此这里使用传统的smtp库来发送email,如果大家有outlook的话,也可以使用outlook的相关win32包来发送邮件,比使用smtp的代码更加简洁。在Email类中,我们需要提供SMTP服务器、发件人、收件人以及密码。其中,SMTP服务器和发件人的邮箱我们要配置在globalsetting.ini文件中。在这里需要注意的是,这里的密码既不是邮箱的登录密码,也不是邮箱的独立密码(仅限QQ邮箱),而是在邮箱中开启SMTP服务时由供应商提供的一个密码。如果这里写成其他的密码,是无法发送邮件的。

sendemail函数接收subject(主题)和content(内容)作为参数。我们要使用MIMEText构造出邮件的结构,然后将From、To和Subject分别填入发件人、收件人以及主题。最后,使用SMTP服务器地址和25端口建立服务器,登录并发送邮件。sendapprovemail则是直接调用这个类,发送给用户一个告知批准的邮件。

有了email模块后,我们就可以写approveuser和logoffuser这两个util函数了。打开userutil.py,输入以下代码:

# util/users/userutil.py

def approveuser(username,usergroup):
    user = session.query(User).filter(User.username == username).first()
    result = 'Fail'
    if type(user) is User:
        user.state = 'Approved'
        user.usergroup = usergroup
        result = insertdata(user)
        if result == 'Success':
            sendapprovemail(user.username,usergroup,user.email)
    return result

def logoffuser(username):
    user = session.query(User).filter(User.username == username).first()
    result = 'Fail'
    if type(user) is User:
        user.state = 'Logoff'
        result = insertdata(user)
    return result

approveuser包含两个参数:username和usergroup。函数功能是将用户的state改为Approved,并将用户组改为参数传入的用户组,在最后发送approve的邮件给用户;logoffuser仅包含用户名,操作也只是把用户状态改为Logoff。

回到user_app.py,输入以下代码实现Approve和Logoff操作:

# user_app.py

class Approve(BaseHandler):
    def post(self):
        userid = self.get_argument('userid')
        username = self.get_argument('username')
        usergroupid = userid + '_group'
        usergroup = self.get_argument(usergroupid)
        result = 'Fail'
        result = approveuser(username,usergroup)
        resultpath = gettemplatepath('result.html')
        if result == 'Success':
            self.redirect('/usermanage')
        else:
            result = '操作失败!'
            self.render(resultpath,result=result)

class LogOff(BaseHandler):
    def post(self):
        username = self.get_argument('username')
        result = 'Fail'
        result = logoffuser(username)
        resultpath = gettemplatepath('result.html')
        if result == 'Success':
            self.redirect('/usermanage')
        else:
            result = '操作失败!'
            self.render(resultpath,result=result)

class LogOut(BaseHandler):
    def get(self):
        self.clear_cookie('currentuser')
        self.redirect('/')

# main.py
routelist = [
    # ...
    (r"/approve",Approve),
    (r"/logoff",LogOff),
    (r"/logout",LogOut),
    # ...
]

由于LogOut比较简单,因此在这里一并列出。Approve和LogOff两个操作均只有post,因为它们不需要显示任何界面。在Approve中,会从表单中获取id,用户名,用户组,并调用approveuser函数来完成批准,最后重定向到用户管理页面;在LogOff中,只需取得用户名便可完成注销用户;而LogOut则是将名为currentuser的cookie清空,并重定向到主页,完成用户登出的操作。

在这篇博客中,我们补全了一些关键的用户系统的功能:用户审批、用户注销以及登出用户,还实现了一个email模块用于发送审批邮件。在下一篇博客中,我们将实现审批考勤以及设置上下级用户的功能,希望大家继续关注~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值