TimeAlbumController.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. import time
  2. from datetime import datetime
  3. import boto3
  4. import botocore
  5. from django.core.paginator import Paginator
  6. from django.views import View
  7. from obs import ObsClient
  8. from Ansjer.config import HUAWEICLOUD_AK, HUAWEICLOUD_SK, HUAWEICLOUD_OBS_SERVER, CONFIG_INFO, CONFIG_CN, CONFIG_TEST, \
  9. AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
  10. from Roomumy.models import TimeAlbum, AlbumMedia, TimeDiary, DiaryAlbumMediaRelation
  11. from Service.CommonService import CommonService
  12. class TimeAlbumView(View):
  13. def get(self, request, *args, **kwargs):
  14. request.encoding = 'utf-8'
  15. operation = kwargs.get('operation')
  16. return self.validation(request.GET, request, operation)
  17. def post(self, request, *args, **kwargs):
  18. request.encoding = 'utf-8'
  19. operation = kwargs.get('operation')
  20. return self.validation(request.POST, request, operation)
  21. def validation(self, request_dict, request, operation):
  22. token_code, user_id, response = CommonService.verify_token_get_user_id(request_dict, request)
  23. if operation == 'clearAlbumMedia': # 删除相册媒体
  24. return self.clear_album_media(response)
  25. else:
  26. if token_code != 0:
  27. return response.json(token_code)
  28. if operation == 'getAlbumPic': # 查询相册列表
  29. return self.get_album_pic(user_id, request_dict, response)
  30. elif operation == 'getTimeDiary': # 获取时光日记列表
  31. return self.get_time_diary(user_id, request_dict, response)
  32. elif operation == 'picLiked': # 喜欢图片
  33. return self.pic_liked(user_id, request_dict, response)
  34. else:
  35. return response.json(414)
  36. def get_album_pic(self, user_id, request_dict, response):
  37. device_id = request_dict.get('deviceId', None)
  38. start_time = request_dict.get('startTime', None)
  39. end_time = request_dict.get('endTime', None)
  40. page = request_dict.get('page', 1) # 当前页码,默认为1
  41. page_size = request_dict.get('pageSize', 10) # 每页显示的记录数,默认为10
  42. # 检查是否提供了uid,如果没有提供返回错误
  43. if device_id is None:
  44. return response.json(444)
  45. try:
  46. # 查询TimeAlbum表,按uid过滤,且如果提供了album_date,则进一步按album_date过滤
  47. time_album_qs = TimeAlbum.objects.filter(device_id=device_id).order_by('-album_date')
  48. if start_time and end_time:
  49. time_album_qs = time_album_qs.filter(album_date__gte=start_time, album_date__lte=end_time)
  50. # 如果没有找到符合条件的TimeAlbum记录,返回错误
  51. if not time_album_qs.exists():
  52. return response.json(0, {})
  53. # 对TimeAlbum结果进行分页
  54. paginator = Paginator(time_album_qs, page_size)
  55. time_albums = paginator.page(page) # 获取当前页的数据
  56. time_album_list = []
  57. # 对每个TimeAlbum,查询相关的AlbumMedia
  58. for time_album in time_albums:
  59. # 查询与当前time_album_id关联的AlbumMedia记录
  60. time_album_info = []
  61. album_media_qs = AlbumMedia.objects.filter(time_album_id=time_album.id).values('id', 'device_id', 'channel',
  62. 'event_time', 'status',
  63. 'storage_location')
  64. if album_media_qs.exists():
  65. for album_media in album_media_qs:
  66. storage_location = album_media['storage_location']
  67. uid = album_media['device_id']
  68. channel = album_media['channel']
  69. event_time = album_media['event_time']
  70. image = self.media_url(storage_location, uid, channel, event_time)
  71. # 判断是否加入时光日记
  72. liked_status = 0
  73. if DiaryAlbumMediaRelation.objects.filter(
  74. album_media_id=album_media['id'],
  75. diary__user_id=user_id
  76. ).exists():
  77. liked_status = 1
  78. time_album_info.append({
  79. 'picId': album_media['id'],
  80. 'image': image,
  81. 'likedStatus': liked_status,
  82. })
  83. time_album_list.append({
  84. 'albumDate': time_album.album_date,
  85. 'albumTitle': time_album.album_title,
  86. 'info': time_album_info
  87. })
  88. # 返回分页结果和数据
  89. return response.json(0, {
  90. 'data': time_album_list,
  91. 'total': paginator.count, # 总记录数
  92. })
  93. except Exception as e:
  94. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  95. def get_time_diary(self, user_id, request_dict, response):
  96. start_time = request_dict.get('startTime', None)
  97. end_time = request_dict.get('endTime', None)
  98. page = int(request_dict.get('page', 1))
  99. page_size = int(request_dict.get('pageSize', 10))
  100. try:
  101. # 基础查询
  102. time_diary_qs = TimeDiary.objects.filter(user_id=user_id).order_by('-diary_date')
  103. # 时间范围过滤
  104. if start_time and end_time:
  105. time_diary_qs = time_diary_qs.filter(diary_date__gte=start_time, diary_date__lte=end_time)
  106. # 分页
  107. paginator = Paginator(time_diary_qs, page_size)
  108. diaries_page = paginator.get_page(page)
  109. diary_data_list = []
  110. for diary in diaries_page:
  111. # 通过中间表获取关联的图片
  112. relations = DiaryAlbumMediaRelation.objects.filter(diary=diary).select_related('album_media')
  113. media_list = []
  114. for relation in relations:
  115. media = relation.album_media
  116. media_list.append({
  117. 'picId': media.id,
  118. 'likeStatus': 1,
  119. 'image': self.media_url(media.storage_location, media.device_id, media.channel,
  120. media.event_time)
  121. })
  122. diary_data_list.append({
  123. 'diary_date': diary.diary_date,
  124. 'info': media_list
  125. })
  126. return response.json(0, {
  127. 'data': diary_data_list,
  128. 'total': paginator.count,
  129. })
  130. except Exception as e:
  131. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  132. @staticmethod
  133. def pic_liked(user_id, request_dict, response):
  134. pic_id = request_dict.get('picId', None)
  135. liked_status = request_dict.get('likedStatus', None)
  136. if not all([pic_id, liked_status]):
  137. return response.json(444)
  138. liked_status = int(liked_status)
  139. try:
  140. album_media = AlbumMedia.objects.filter(id=pic_id).first()
  141. if not album_media:
  142. return response.json(404, 'pic not found')
  143. # 获取相册的日期
  144. time_diary_qs = AlbumMedia.objects.filter(id=pic_id).values('time_album_id', 'event_time', 'status')
  145. if not time_diary_qs.exists():
  146. return response.json(173)
  147. event_time = time_diary_qs[0]['event_time']
  148. dt = datetime.fromtimestamp(event_time)
  149. dt_zero = datetime(dt.year, dt.month, dt.day)
  150. diary_date = int(dt_zero.timestamp())
  151. # 查找或创建用户今天的 TimeDiary
  152. time_diary, created = TimeDiary.objects.get_or_create(
  153. user_id=user_id,
  154. diary_date=diary_date,
  155. defaults={
  156. 'created_time': int(time.time()),
  157. 'updated_time': int(time.time())
  158. }
  159. )
  160. if liked_status == 1:
  161. # 添加到 TimeDiary(中间表中插入)
  162. DiaryAlbumMediaRelation.objects.get_or_create(
  163. diary=time_diary,
  164. album_media=album_media,
  165. defaults={
  166. 'created_time': int(time.time()),
  167. 'updated_time': int(time.time())
  168. }
  169. )
  170. time_diary_qs.update(status=2, updated_time=int(time.time()))
  171. elif liked_status == 0:
  172. # 从中间表移除
  173. DiaryAlbumMediaRelation.objects.filter(diary=time_diary, album_media=album_media).delete()
  174. if DiaryAlbumMediaRelation.objects.filter(diary=time_diary).count() == 0:
  175. time_diary.delete()
  176. if not DiaryAlbumMediaRelation.objects.filter(album_media=album_media).exists():
  177. time_diary_qs.update(status=1, updated_time=int(time.time()))
  178. return response.json(0)
  179. except Exception as e:
  180. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  181. @staticmethod
  182. def media_url(storage_location, uid, channel, event_time):
  183. if storage_location == 2:
  184. obj_name = f'roomumy/albumMedia/{uid}/{channel}/{event_time}.jpeg'
  185. if CONFIG_INFO == CONFIG_CN or CONFIG_INFO == CONFIG_TEST:
  186. aws_client = boto3.client(
  187. 's3',
  188. aws_access_key_id=AWS_ACCESS_KEY_ID[0],
  189. aws_secret_access_key=AWS_SECRET_ACCESS_KEY[0],
  190. region_name='cn-northwest-1'
  191. )
  192. else:
  193. aws_client = boto3.client(
  194. 's3',
  195. aws_access_key_id=AWS_ACCESS_KEY_ID[1],
  196. aws_secret_access_key=AWS_SECRET_ACCESS_KEY[1],
  197. region_name='cn-northwest-1'
  198. )
  199. params = {'Key': obj_name, 'Bucket': 'ansjerfilemanager'}
  200. media_url = aws_client.generate_presigned_url(
  201. 'get_object', Params=params, ExpiresIn=300)
  202. elif storage_location == 5:
  203. obj_name = f'roomumy/albumMedia/{uid}/{channel}/{event_time}.jpeg'
  204. obs_client = ObsClient(
  205. access_key_id=HUAWEICLOUD_AK, secret_access_key=HUAWEICLOUD_SK, server=HUAWEICLOUD_OBS_SERVER)
  206. create_res = obs_client.createSignedUrl(
  207. method='GET', bucketName="asj-app", objectKey=obj_name, expires=600)
  208. media_url = create_res.signedUrl
  209. else:
  210. media_url = ''
  211. return media_url
  212. @staticmethod
  213. def clear_album_media(response):
  214. # 获取当前时间
  215. current_time = int(time.time()) - 2592000
  216. # 预加载关联的TimeAlbum对象
  217. album_media_qs = AlbumMedia.objects.filter(
  218. status=1,
  219. event_time__lt=current_time
  220. )
  221. # 如果没有需要处理的数据,直接返回
  222. if not album_media_qs.exists():
  223. return response.json(0)
  224. # 初始化 Huawei Cloud 的 ObsClient
  225. obs_client = ObsClient(
  226. access_key_id=HUAWEICLOUD_AK,
  227. secret_access_key=HUAWEICLOUD_SK,
  228. server=HUAWEICLOUD_OBS_SERVER
  229. )
  230. # 根据配置选择初始化 AWS 客户端
  231. aws_client_config = {
  232. 'aws_access_key_id': AWS_ACCESS_KEY_ID[0] if CONFIG_INFO in [CONFIG_CN, CONFIG_TEST] else AWS_ACCESS_KEY_ID[1],
  233. 'aws_secret_access_key': AWS_SECRET_ACCESS_KEY[0] if CONFIG_INFO in [CONFIG_CN, CONFIG_TEST] else AWS_SECRET_ACCESS_KEY[1],
  234. 'region_name': 'cn-northwest-1' if CONFIG_INFO in [CONFIG_CN, CONFIG_TEST] else 'us-east-1'
  235. }
  236. aws_client = boto3.client('s3', **aws_client_config)
  237. # 准备批量删除的对象
  238. aws_objects_to_delete = []
  239. obs_objects_to_delete = []
  240. time_album_ids_to_check = set()
  241. album_media_ids_to_delete = []
  242. # 收集需要删除的对象和时间相册ID
  243. for album_media in album_media_qs:
  244. uid = album_media.device_id
  245. event_time = album_media.event_time
  246. obj_name = f'roomumy/albumMedia/{uid}/{album_media.channel}/{event_time}.jpeg'
  247. album_media_ids_to_delete.append(album_media.id)
  248. if album_media.time_album_id:
  249. time_album_ids_to_check.add(album_media.time_album_id)
  250. if album_media.storage_location == 2:
  251. aws_objects_to_delete.append({'Key': obj_name})
  252. elif album_media.storage_location == 5:
  253. obs_objects_to_delete.append(obj_name)
  254. # 批量删除AWS对象
  255. if aws_objects_to_delete:
  256. # AWS S3支持批量删除,最多1000个对象每次
  257. for i in range(0, len(aws_objects_to_delete), 1000):
  258. batch = aws_objects_to_delete[i:i + 1000]
  259. aws_client.delete_objects(
  260. Bucket='ansjerfilemanager',
  261. Delete={'Objects': batch}
  262. )
  263. # 删除华为OBS对象
  264. if obs_objects_to_delete:
  265. for obj_name in obs_objects_to_delete:
  266. obs_client.deleteObject(bucketName="asj-app", objectKey=obj_name)
  267. # 检查需要删除的TimeAlbum
  268. if time_album_ids_to_check:
  269. # 查询TimeAlbum关联的AlbumMedia
  270. time_albums_with_media = AlbumMedia.objects.filter(
  271. time_album_id__in=time_album_ids_to_check
  272. ).exclude(
  273. id__in=album_media_ids_to_delete
  274. ).values_list('time_album_id', flat=True).distinct()
  275. # 找出没有关联媒体的TimeAlbum
  276. time_albums_to_delete = set(time_album_ids_to_check) - set(time_albums_with_media)
  277. # 批量删除TimeAlbum
  278. if time_albums_to_delete:
  279. TimeAlbum.objects.filter(id__in=time_albums_to_delete).delete()
  280. # 处理完所有项后,删除数据库中的记录
  281. album_media_qs.delete()
  282. return response.json(0)