import time from datetime import datetime import boto3 import botocore from django.core.paginator import Paginator from django.views import View from obs import ObsClient from Ansjer.config import HUAWEICLOUD_AK, HUAWEICLOUD_SK, HUAWEICLOUD_OBS_SERVER, CONFIG_INFO, CONFIG_CN, CONFIG_TEST, \ AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY from Roomumy.models import TimeAlbum, AlbumMedia, TimeDiary, DiaryAlbumMediaRelation from Service.CommonService import CommonService class TimeAlbumView(View): def get(self, request, *args, **kwargs): request.encoding = 'utf-8' operation = kwargs.get('operation') return self.validation(request.GET, request, operation) def post(self, request, *args, **kwargs): request.encoding = 'utf-8' operation = kwargs.get('operation') return self.validation(request.POST, request, operation) def validation(self, request_dict, request, operation): token_code, user_id, response = CommonService.verify_token_get_user_id(request_dict, request) if operation == 'clearAlbumMedia': # 删除相册媒体 return self.clear_album_media(response) else: if token_code != 0: return response.json(token_code) if operation == 'getAlbumPic': # 查询相册列表 return self.get_album_pic(user_id, request_dict, response) elif operation == 'getTimeDiary': # 获取时光日记列表 return self.get_time_diary(user_id, request_dict, response) elif operation == 'picLiked': # 喜欢图片 return self.pic_liked(user_id, request_dict, response) else: return response.json(414) def get_album_pic(self, user_id, request_dict, response): device_id = request_dict.get('deviceId', None) start_time = request_dict.get('startTime', None) end_time = request_dict.get('endTime', None) page = request_dict.get('page', 1) # 当前页码,默认为1 page_size = request_dict.get('pageSize', 10) # 每页显示的记录数,默认为10 # 检查是否提供了uid,如果没有提供返回错误 if device_id is None: return response.json(444) try: # 查询TimeAlbum表,按uid过滤,且如果提供了album_date,则进一步按album_date过滤 time_album_qs = TimeAlbum.objects.filter(device_id=device_id).order_by('-album_date') if start_time and end_time: time_album_qs = time_album_qs.filter(album_date__gte=start_time, album_date__lte=end_time) # 如果没有找到符合条件的TimeAlbum记录,返回错误 if not time_album_qs.exists(): return response.json(0, {}) # 对TimeAlbum结果进行分页 paginator = Paginator(time_album_qs, page_size) time_albums = paginator.page(page) # 获取当前页的数据 time_album_list = [] # 对每个TimeAlbum,查询相关的AlbumMedia for time_album in time_albums: # 查询与当前time_album_id关联的AlbumMedia记录 time_album_info = [] album_media_qs = AlbumMedia.objects.filter(time_album_id=time_album.id).values('id', 'device_id', 'channel', 'event_time', 'status', 'storage_location') if album_media_qs.exists(): for album_media in album_media_qs: storage_location = album_media['storage_location'] uid = album_media['device_id'] channel = album_media['channel'] event_time = album_media['event_time'] image = self.media_url(storage_location, uid, channel, event_time) # 判断是否加入时光日记 liked_status = 0 if DiaryAlbumMediaRelation.objects.filter( album_media_id=album_media['id'], diary__user_id=user_id ).exists(): liked_status = 1 time_album_info.append({ 'picId': album_media['id'], 'image': image, 'likedStatus': liked_status, }) time_album_list.append({ 'albumDate': time_album.album_date, 'albumTitle': time_album.album_title, 'info': time_album_info }) # 返回分页结果和数据 return response.json(0, { 'data': time_album_list, 'total': paginator.count, # 总记录数 }) except Exception as e: return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e))) def get_time_diary(self, user_id, request_dict, response): start_time = request_dict.get('startTime', None) end_time = request_dict.get('endTime', None) page = int(request_dict.get('page', 1)) page_size = int(request_dict.get('pageSize', 10)) try: # 基础查询 time_diary_qs = TimeDiary.objects.filter(user_id=user_id).order_by('-diary_date') # 时间范围过滤 if start_time and end_time: time_diary_qs = time_diary_qs.filter(diary_date__gte=start_time, diary_date__lte=end_time) # 分页 paginator = Paginator(time_diary_qs, page_size) diaries_page = paginator.get_page(page) diary_data_list = [] for diary in diaries_page: # 通过中间表获取关联的图片 relations = DiaryAlbumMediaRelation.objects.filter(diary=diary).select_related('album_media') media_list = [] for relation in relations: media = relation.album_media media_list.append({ 'picId': media.id, 'likeStatus': 1, 'image': self.media_url(media.storage_location, media.device_id, media.channel, media.event_time) }) diary_data_list.append({ 'diary_date': diary.diary_date, 'info': media_list }) return response.json(0, { 'data': diary_data_list, 'total': paginator.count, }) except Exception as e: return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e))) @staticmethod def pic_liked(user_id, request_dict, response): pic_id = request_dict.get('picId', None) liked_status = request_dict.get('likedStatus', None) if not all([pic_id, liked_status]): return response.json(444) liked_status = int(liked_status) try: album_media = AlbumMedia.objects.filter(id=pic_id).first() if not album_media: return response.json(404, 'pic not found') # 获取相册的日期 time_diary_qs = AlbumMedia.objects.filter(id=pic_id).values('time_album_id', 'event_time', 'status') if not time_diary_qs.exists(): return response.json(173) event_time = time_diary_qs[0]['event_time'] dt = datetime.fromtimestamp(event_time) dt_zero = datetime(dt.year, dt.month, dt.day) diary_date = int(dt_zero.timestamp()) # 查找或创建用户今天的 TimeDiary time_diary, created = TimeDiary.objects.get_or_create( user_id=user_id, diary_date=diary_date, defaults={ 'created_time': int(time.time()), 'updated_time': int(time.time()) } ) if liked_status == 1: # 添加到 TimeDiary(中间表中插入) DiaryAlbumMediaRelation.objects.get_or_create( diary=time_diary, album_media=album_media, defaults={ 'created_time': int(time.time()), 'updated_time': int(time.time()) } ) time_diary_qs.update(status=2, updated_time=int(time.time())) elif liked_status == 0: # 从中间表移除 DiaryAlbumMediaRelation.objects.filter(diary=time_diary, album_media=album_media).delete() if DiaryAlbumMediaRelation.objects.filter(diary=time_diary).count() == 0: time_diary.delete() if not DiaryAlbumMediaRelation.objects.filter(album_media=album_media).exists(): time_diary_qs.update(status=1, updated_time=int(time.time())) return response.json(0) except Exception as e: return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e))) @staticmethod def media_url(storage_location, uid, channel, event_time): if storage_location == 2: obj_name = f'roomumy/albumMedia/{uid}/{channel}/{event_time}.jpeg' if CONFIG_INFO == CONFIG_CN or CONFIG_INFO == CONFIG_TEST: aws_client = boto3.client( 's3', aws_access_key_id=AWS_ACCESS_KEY_ID[0], aws_secret_access_key=AWS_SECRET_ACCESS_KEY[0], region_name='cn-northwest-1' ) else: aws_client = boto3.client( 's3', aws_access_key_id=AWS_ACCESS_KEY_ID[1], aws_secret_access_key=AWS_SECRET_ACCESS_KEY[1], region_name='cn-northwest-1' ) params = {'Key': obj_name, 'Bucket': 'ansjerfilemanager'} media_url = aws_client.generate_presigned_url( 'get_object', Params=params, ExpiresIn=300) elif storage_location == 5: obj_name = f'roomumy/albumMedia/{uid}/{channel}/{event_time}.jpeg' obs_client = ObsClient( access_key_id=HUAWEICLOUD_AK, secret_access_key=HUAWEICLOUD_SK, server=HUAWEICLOUD_OBS_SERVER) create_res = obs_client.createSignedUrl( method='GET', bucketName="asj-app", objectKey=obj_name, expires=600) media_url = create_res.signedUrl else: media_url = '' return media_url @staticmethod def clear_album_media(response): # 获取当前时间 current_time = int(time.time()) - 2592000 # 预加载关联的TimeAlbum对象 album_media_qs = AlbumMedia.objects.filter( status=1, event_time__lt=current_time ) # 如果没有需要处理的数据,直接返回 if not album_media_qs.exists(): return response.json(0) # 初始化 Huawei Cloud 的 ObsClient obs_client = ObsClient( access_key_id=HUAWEICLOUD_AK, secret_access_key=HUAWEICLOUD_SK, server=HUAWEICLOUD_OBS_SERVER ) # 根据配置选择初始化 AWS 客户端 aws_client_config = { 'aws_access_key_id': AWS_ACCESS_KEY_ID[0] if CONFIG_INFO in [CONFIG_CN, CONFIG_TEST] else AWS_ACCESS_KEY_ID[1], 'aws_secret_access_key': AWS_SECRET_ACCESS_KEY[0] if CONFIG_INFO in [CONFIG_CN, CONFIG_TEST] else AWS_SECRET_ACCESS_KEY[1], 'region_name': 'cn-northwest-1' if CONFIG_INFO in [CONFIG_CN, CONFIG_TEST] else 'us-east-1' } aws_client = boto3.client('s3', **aws_client_config) # 准备批量删除的对象 aws_objects_to_delete = [] obs_objects_to_delete = [] time_album_ids_to_check = set() album_media_ids_to_delete = [] # 收集需要删除的对象和时间相册ID for album_media in album_media_qs: uid = album_media.device_id event_time = album_media.event_time obj_name = f'roomumy/albumMedia/{uid}/{album_media.channel}/{event_time}.jpeg' album_media_ids_to_delete.append(album_media.id) if album_media.time_album_id: time_album_ids_to_check.add(album_media.time_album_id) if album_media.storage_location == 2: aws_objects_to_delete.append({'Key': obj_name}) elif album_media.storage_location == 5: obs_objects_to_delete.append(obj_name) # 批量删除AWS对象 if aws_objects_to_delete: # AWS S3支持批量删除,最多1000个对象每次 for i in range(0, len(aws_objects_to_delete), 1000): batch = aws_objects_to_delete[i:i + 1000] aws_client.delete_objects( Bucket='ansjerfilemanager', Delete={'Objects': batch} ) # 删除华为OBS对象 if obs_objects_to_delete: for obj_name in obs_objects_to_delete: obs_client.deleteObject(bucketName="asj-app", objectKey=obj_name) # 检查需要删除的TimeAlbum if time_album_ids_to_check: # 查询TimeAlbum关联的AlbumMedia time_albums_with_media = AlbumMedia.objects.filter( time_album_id__in=time_album_ids_to_check ).exclude( id__in=album_media_ids_to_delete ).values_list('time_album_id', flat=True).distinct() # 找出没有关联媒体的TimeAlbum time_albums_to_delete = set(time_album_ids_to_check) - set(time_albums_with_media) # 批量删除TimeAlbum if time_albums_to_delete: TimeAlbum.objects.filter(id__in=time_albums_to_delete).delete() # 处理完所有项后,删除数据库中的记录 album_media_qs.delete() return response.json(0)