使用 GitHub Actions 定时发送空闲教室信息邮件

目录

本文章已过时

书接上回 -> URP教务系统自动登录

我可以用 GitHub Actions 写一个定时任务,每天早上把当天的空闲教室信息写进邮件发给我。

查询当天空闲教室

获取当天日期

这个说起来简单,但是还是有点坑,GitHub Actions 使用的 UTC 标准时间,我们这边的时区是 UTC+8,快8个小时,所以如果是早上8点之前执行的话,获取的还是昨天的信息。这里的时间要改。

定义三个函数,方便后续使用

# only for 2022-2023 1
def get_week_num(d=datetime.now(pytz.timezone('Asia/Shanghai'))):
    return d.isocalendar().week - 34

# mon -> 1, ect..
def get_weekday(d=datetime.now(pytz.timezone('Asia/Shanghai'))):
    return datetime.weekday(d) + 1

def get_format_date(d=datetime.now(pytz.timezone('Asia/Shanghai'))):
    return d.strftime('%Y年%m月%d日')

这里我们使用 pytz 库来获取 Asia/Shanghai 时区的当前时间。

  • get_week_num() 函数用于获取当前的周数,这里的周数是学校的教学周,正好这学期2023年就没有教学周了,所以简单粗暴的相减即可
  • get_weekday() 函数获取当前是一周的第几天

根据日期进行查询

定义每一小节的时间段

class_time = {
  1: '第1节 08:00 08:45',
  2: '第2节 08:50 09:35',
  3: '第3节 09:50 10:35',
  ...
}

因为是每天的空闲教室信息,这里需要批量查询每一小节的教室使用情况。其他校区的同学可自行添加其他校区的信息。

def search_today(self):
  campus_code = 3             # 校区代码
  tea_codes = [61, 62]        # 教学楼代码列表
  week_num = util.get_weekday()    # 周数
  results = []                # 结果集
  for tea_code in tea_codes:
    classrooms = []
    for i in range(1, 13):
      section = str(week_num) + '/' + str(i)  # 节数
      param = {
        'weeks': util.get_week_num(),
        ...
      }
      ret = self.search_free_classroom(param)
      classroom = {
        'time': class_time.get(i),
        'rooms': ", ".join(ret),
      }
      classrooms.append(classroom)
      results.append({
        'tea': teaching_num.get(tea_code),
        'classrooms': classrooms,
      })
  return results

创建邮件模板

这里是个大坑,一开始我不知道邮件HTML要求特别严格,有的邮件客户端甚至会过滤掉 <head> 里面的 <style> 外部样式

更多的内容可以参考阮一峰的博客 HTML Email 编写指南

我使用了 JinJa2 作为HMTL文件的模板渲染语言。

<h3 style="text-align: center;">空闲教室</h3>
<p style="text-align: center; padding-bottom: 20px; color: #586069">今日({{ daytime }})</p>
{% for result in results %}
<p style="margin-left: 20px">{{ result.tea }}空闲教室</p>
<table class="table table-striped table-bordered" border="1" style="border-collapse: collapse; margin-bottom: 30px">
  <thead><tr>
    <th class="content-block" style="width: 130px">节次</th>
    <th>空闲教室</th>
  </tr></thead>
  <tbody>
    {% for classroom in result.classrooms %}
    <tr>
      <td class="content-block" style="width: 130px"><p>{{ classroom.time }}</p></td>
      <td style="color: #586069">{{ classroom.rooms }}</td>
    </tr>
    {% endfor %}
  </tbody>
</table>
{% endfor %}

渲染的内容包括两个方面:

  • daytime: 当天时间的格式化字符串
  • results: 查询结果的Map对象

渲染模板部分的代码:

def write2html(params, template_file=TEMPLATE_FILE, html_file=HTML_FILE):
  current_directory = os.path.dirname(os.path.abspath(__file__))
  env = Environment(loader=FileSystemLoader(current_directory))
  res = env.get_template(template_file).render(params)
  test = codecs.open(html_file, 'w', 'utf-8')
  test.write(res)
  test.close()

函数 write2html() 接受待渲染的内容 params,读取模板文件 template_file,将内容输出到文件 html_file 中。

重构代码

为了方便测试和后续部署,这里我们的URP教务系统的用户名和密码不再硬编码到文件中,而是使用命令行参数的形式进行读取。

def parse_params():
  parser = argparse.ArgumentParser()
  parser.add_argument("-u", "--username", dest="username")
  parser.add_argument("-p", "--password", dest="password")
  args = parser.parse_args()
  return args.__getattribute__('username'), args.__getattribute__('password')

运行时只需要使用下列命令即可

python main.py -u <username> -p <password>

添加定时任务

GitHub Actions makes it easy to automate all your software workflows, now with world-class CI/CD. Build, test, and deploy your code right from GitHub. Make code reviews, branch management, and issue triaging work the way you want.

我们可以在 GitHub Actions 上创建自己的 workflow ,命名为 send mail

更多关于 GitHub Actions 的内容,可以参考官方文档 https://docs.github.com/cn/actions

这里简单介绍一下构建流程:

  • 拉取 ubuntu 镜像
  • 切换到 actions 分支
  • 创建 python 工作环境
  • 安装依赖
  • 执行 python 脚本
  • 发送邮件
name: send mail
on:
  schedule:
    - cron: "20 22 * * *"
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    ...
    - name: install dependencies
      run: |
        pip install -r requirement.txt        
    - name: execute py script
      run: |
        python main.py -u $Username -p $Password        
      env:
        Username: ${{ secrets.HHU_USERNAME }}
        Password: ${{ secrets.HHU_PASSWORD }}
    - name: send email
      uses: dawidd6/action-send-mail@v2
      with:
        server_address: smtp.qcloudmail.com
        server_port: 465
        username: ${{ secrets.MAIL_USERNAME }}
        password: ${{ secrets.MAIL_PASSWORD }}
        subject: 今日空闲教室
        body: file://template/result.html
        to: ${{ secrets.EMAIL }}
        from: GitHub Actions
        content_type: text/html

为了防止密码泄露,我们还要在仓库添加5个密钥:

  • HHU_USERNAME: URP 教务系统用户名

  • HHU_PASSWORD: URP 教务系统密码

  • MAIL_USERNAME: 邮箱服务发件邮箱

  • MAIL_PASSWORD: 邮箱服务发件邮箱授权密码

  • EMAIL: 收件邮箱

另外,根据不同的邮件服务,server_addressserver_port 一般也不同,需要自行配置。我们将运行时间定为北京时间每天早上6:20,为了方便查看效果,测试时可以另外设置为 push 时触发。

差不多就是这样,每天早上起床就可以收到邮件,完美。

以上。


comments powered by Disqus