Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Appointment/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ def remove_hidden(self, request, queryset: QuerySet[Participant]):
return self.message_user(request, '操作成功!')


@admin.register(RoomClass)
class RoomClassAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'sort_idx',)
ordering = ('sort_idx',)
# For many-to-many fields
filter_horizontal = ('rooms',)

@admin.register(Room)
class RoomAdmin(admin.ModelAdmin):
list_display = ('Rid', 'Rtitle', 'Rmin', 'Rmax', 'Rstart', 'Rfinish',
Expand Down
11 changes: 6 additions & 5 deletions Appointment/hardware_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@

from Appointment.models import Room, Appoint, Participant, CardCheckInfo
from Appointment.extern.wechat import notify_user
from Appointment.utils.utils import (
door2room, ip2room,
check_temp_appoint,
)
from Appointment.utils.utils import door2room, ip2room
from Appointment.utils.log import logger
import Appointment.utils.web_func as web_func
from Appointment.utils.identity import get_participant
Expand Down Expand Up @@ -266,9 +263,13 @@ def _temp_failed(message: str, record_temp=True):
# 当前无预约

# 房间不可以临时预约
if not check_temp_appoint(room):
if not room.quick_reservable:
return _temp_failed(f"该房间不可临时预约", False)

# 无权限
if not room.check_user_perm(student.Sid):
return _temp_failed(f"无权预约", False)

# 该房间可以用于临时预约
start, finish, timeid, valid = _temp_appoint_valid(room)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Generated by Django 5.0.9 on 2024-12-27 16:04

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("Appointment", "0003_alter_appoint_options_alter_appoint_areason"),
]

operations = [
migrations.AddField(
model_name="room",
name="image",
field=models.ImageField(
null=True, upload_to="room_images", verbose_name="房间图片"
),
),
migrations.AddField(
model_name="room",
name="quick_reservable",
field=models.BooleanField(default=False, verbose_name="支持临时预约"),
),
migrations.CreateModel(
name="RoomClass",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("sort_idx", models.SmallIntegerField(verbose_name="主页排序")),
(
"name",
models.CharField(max_length=32, unique=True, verbose_name="类别名称"),
),
(
"description",
models.CharField(
blank=True, default="", max_length=256, verbose_name="类别描述"
),
),
(
"rooms",
models.ManyToManyField(
db_index=True,
related_name="classes",
to="Appointment.room",
verbose_name="房间列表",
),
),
],
options={
"verbose_name": "房间类别",
"verbose_name_plural": "房间类别",
},
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Generated by Django 5.0.9 on 2024-12-28 12:28

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("Appointment", "0004_room_image_room_quick_reservable_roomclass"),
("auth", "0012_alter_user_first_name_max_length"),
]

operations = [
migrations.AlterModelOptions(
name="room",
options={
"ordering": ["Rid"],
"permissions": [("can_book_example_rooms", "可预约样例房间")],
"verbose_name": "房间",
"verbose_name_plural": "房间",
},
),
migrations.AddField(
model_name="room",
name="required_perm",
field=models.ForeignKey(
blank=True,
default=None,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="auth.permission",
),
),
]
59 changes: 33 additions & 26 deletions Appointment/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@
from django.db.models import QuerySet, Q
from django.dispatch import receiver
from django.db import transaction
from django.contrib.auth.models import Permission

from utils.models.descriptor import admin_only
from utils.models.choice import choice, CustomizedDisplay, DefaultDisplay
from utils.models.manager import ManyRelatedManager
from utils.models.permission import PermissionModelBase, BasePermission
from generic.models import User
from Appointment.config import appointment_config as CONFIG
from Appointment.apps import AppointmentConfig

__all__ = [
'User',
'College_Announcement',
'Participant',
'RoomClass',
'Room',
'Appoint',
'LongTermAppoint',
Expand Down Expand Up @@ -105,15 +108,6 @@ def activated(self):
'''只保留所有可用的房间'''
return self.filter(Rstatus__in=[Room.Status.UNLIMITED, Room.Status.PERMITTED])

def basement_only(self):
'''只保留所有地下室的房间'''
return self.exclude(Rid__icontains="R")

def russian_only(self):
'''只保留所有俄文楼的房间'''
return self.filter(Rid__icontains="R")


class RoomManager(models.Manager['Room']):
def get_queryset(self) -> RoomQuerySet:
return RoomQuerySet(self.model, using=self._db, hints=self._hints)
Expand All @@ -127,33 +121,35 @@ def permitted(self):
def unlimited(self):
return self.get_queryset().unlimited()

def function_rooms(self):
'''获取所有可预约功能房'''
titles = ['航模', '绘画', '书法', '活动']
title_query = ~Q(Rtitle__icontains="研讨")
title_query |= Q(Rtitle__icontains="/")
for room_title in titles:
title_query |= Q(Rtitle__icontains=room_title)
return self.get_queryset().permitted().basement_only().filter(title_query)
def interview_room_ids(self):
return set()

def talk_rooms(self):
'''获取所有研讨室'''
return self.get_queryset().permitted().filter(Rtitle__icontains="研讨")

def russian_rooms(self):
'''获取所有可预约俄文楼教室'''
return self.get_queryset().permitted().russian_only()
class RoomClass(models.Model):
class Meta:
verbose_name = '房间类别'
verbose_name_plural = verbose_name

def interview_room_ids(self):
'''获取所有可面试俄文楼教室'''
return set()
sort_idx = models.SmallIntegerField('主页排序')
name = models.CharField('类别名称', max_length=32, unique=True)
description = models.CharField(
'类别描述', max_length=256, blank=True, default='')
rooms = models.ManyToManyField(
'Room', verbose_name='房间列表', db_index=True, related_name='classes')

# Used for room's many-to-many field
def __str__(self):
return self.name

class Room(models.Model):
class Meta:
verbose_name = '房间'
verbose_name_plural = verbose_name
ordering = ['Rid']
# 可以临时修改来生成 migrations 文件,但具体的权限不要留在 develop 分支里
permissions = [
('can_book_example_rooms', '可预约样例房间'),
]

# 房间编号我不确定是否需要。如果地下室有门牌的话(例如B101)保留房间编号比较好
# 如果删除Rid记得把Rtitle设置成主键
Expand All @@ -165,12 +161,23 @@ class Meta:
Rfinish = models.TimeField('最迟预约时间')
Rlatest_time = models.DateTimeField("摄像头心跳", auto_now_add=True)
Rpresent = models.IntegerField('目前人数', default=0)
image = models.ImageField('房间图片', upload_to='room_images', null=True)
# 不使用 “perms”,避免又一个 many-to-many 的表
required_perm = models.ForeignKey(
Permission, default=None, null=True, blank=True,
on_delete=models.SET_NULL)

def check_user_perm(self, user: User) -> bool:
'''检查用户是否有权限预约此房间'''
return self.required_perm is None or user.has_perm(
f'{AppointmentConfig.name}.{self.required_perm.codename}')

# Rstatus 标记当前房间是否允许预约,可由管理员修改
class Status(models.IntegerChoices):
PERMITTED = 0, '允许预约' # 允许预约
UNLIMITED = 1, '无需预约' # 允许使用
FORBIDDEN = 2, '禁止使用' # 禁止使用
quick_reservable = models.BooleanField('支持临时预约', default=False)

Rstatus = models.SmallIntegerField('房间状态', choices=Status.choices, default=0)

Expand Down
4 changes: 0 additions & 4 deletions Appointment/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,6 @@ def door2room(door):
return door_room_dict[door]


def check_temp_appoint(room: Room) -> bool:
return '研讨' in room.Rtitle


def get_conflict_appoints(appoint: Appoint, times: int = 1,
interval: int = 1, week_offset: int = 0,
exclude_this: bool = False,
Expand Down
Loading