拍爱

views.py 35KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094
  1. # -*- coding: utf-8 -*-
  2. from __future__ import division
  3. import os
  4. import random
  5. import records
  6. import shortuuid
  7. from curtail_uuid import CurtailUUID
  8. from django.conf import settings
  9. from django.core.files.storage import default_storage
  10. from django.db import connection, transaction
  11. from django.shortcuts import render
  12. from logit import logit
  13. from rest_framework import viewsets
  14. from TimeConvert import TimeConvert as tc
  15. from account.models import UserInfo
  16. from group.models import GroupInfo, GroupPhotoInfo, GroupUserInfo, PhotoCommentInfo, PhotoThumbUpInfo
  17. from group.serializers import GroupInfoSerializer, GroupPhotoInfoSerializer, GroupUserInfoSerializer
  18. from message.models import UserMessageInfo
  19. from utils.error.errno_utils import GroupPhotoStatusCode, GroupStatusCode, GroupUserStatusCode, UserStatusCode
  20. from utils.error.response_utils import response
  21. from utils.page_utils import pagination
  22. from utils.redis.rgroup import (del_group_photo_thumbup_flag, get_group_info, get_group_photo_comment_list,
  23. get_group_photo_data, get_group_photo_thumbup_flag, get_group_photo_thumbup_list,
  24. get_group_photo_watchers, get_group_users_info, set_group_info,
  25. set_group_photo_comment_list, set_group_photo_data, set_group_photo_thumbup_flag,
  26. set_group_photo_thumbup_list, set_group_users_info)
  27. from utils.redis.rkeys import (GROUP_LAST_PHOTO_PK, GROUP_PHOTO_WATCHER_SET, GROUP_USERS_APPLYING_SET,
  28. GROUP_USERS_DELETED_SET, GROUP_USERS_PASSED_SET, GROUP_USERS_QUIT_SET,
  29. GROUP_USERS_REFUSED_SET, LENSMAN_PHOTO_HAGGLE_TIMES, LENSMAN_PHOTO_PRICE)
  30. from utils.redis.rorder import get_lensman_order_record
  31. from utils.redis.rprice import get_lensman_price_fixed
  32. from utils.sql.raw import PAI2_HOME_API
  33. from utils.thumbnail_utils import make_thumbnail
  34. from utils.time_utils import origin_expired_stamps
  35. from utils.url_utils import img_url, share_url
  36. # db = records.Database(settings.DATABASE_URL['default'])
  37. r = settings.REDIS_CACHE
  38. @logit
  39. @transaction.atomic
  40. def group_create_api(request):
  41. """
  42. 群组创建
  43. :param request:
  44. :return:
  45. """
  46. user_id = request.POST.get('user_id', '')
  47. group_name = request.POST.get('group_name', '')
  48. group_default_avatar = int(request.POST.get('group_default_avatar', 0))
  49. # 用户校验
  50. try:
  51. user = UserInfo.objects.get(user_id=user_id)
  52. except UserInfo.DoesNotExist:
  53. return response(UserStatusCode.USER_NOT_FOUND)
  54. # 群组唯一标识
  55. group_id = CurtailUUID.uuid(GroupInfo, 'group_id')
  56. # 群组记录创建
  57. group = GroupInfo.objects.create(
  58. group_id=group_id,
  59. admin_id=user_id,
  60. group_name=group_name,
  61. group_default_avatar=group_default_avatar,
  62. group_from=GroupInfo.APP_GROUP,
  63. )
  64. # Redis 群组数据缓存
  65. group_info = set_group_info(group)
  66. # 群组用户记录创建
  67. GroupUserInfo.objects.create(
  68. group_id=group_id,
  69. user_id=user_id,
  70. nickname=user.final_nickname,
  71. avatar=user.avatar,
  72. admin=True,
  73. user_status=GroupUserInfo.PASSED,
  74. passed_at=tc.utc_datetime(),
  75. )
  76. # Redis 群组用户数据缓存
  77. group_users = set_group_users_info(group)
  78. # Redis 群组通过集合缓存
  79. r.sadd(GROUP_USERS_PASSED_SET % group_id, user_id)
  80. return response(200, 'Create Group Success', u'群组创建成功', {
  81. 'group_id': group_id,
  82. 'group': group_info,
  83. 'users': group_users,
  84. })
  85. @logit
  86. def group_detail_api(request):
  87. """
  88. 群组详情
  89. :param request:
  90. :return:
  91. """
  92. group_id = request.POST.get('group_id', '')
  93. user_id = request.POST.get('user_id', '')
  94. return response(200, 'Get Group Detail Info Success', u'获取群组详情成功', {
  95. 'group_id': group_id,
  96. 'group': get_group_info(group_id),
  97. 'users': get_group_users_info(group_id, user_id),
  98. })
  99. @logit
  100. def group_update_api(request):
  101. """
  102. 群组更新
  103. :param request:
  104. :return:
  105. """
  106. group_id = request.POST.get('group_id', '')
  107. admin_id = request.POST.get('admin_id', '') or request.POST.get('user_id', '')
  108. group_name = request.POST.get('group_name', '')
  109. group_desc = request.POST.get('group_desc', '')
  110. group_avatar = request.FILES.get('group_avatar', '')
  111. # 群组校验
  112. try:
  113. group = GroupInfo.objects.get(group_id=group_id)
  114. except GroupInfo.DoesNotExist:
  115. return response(GroupStatusCode.GROUP_NOT_FOUND)
  116. # 权限校验
  117. if group.admin_id != admin_id:
  118. return response(GroupStatusCode.NO_UPDATE_PERMISSION)
  119. # 群组名称更新
  120. if group_name:
  121. group.group_name = group_name
  122. # 群组描述更新
  123. if group_desc:
  124. group.group_desc = group_desc
  125. # 群组头像更新
  126. if group_avatar:
  127. _, extension = os.path.splitext(group_avatar.name)
  128. group_avatar_path = 'group/{uuid}_{extension}'.format(uuid=shortuuid.uuid(), extension=extension)
  129. if default_storage.exists(group_avatar_path):
  130. default_storage.delete(group_avatar_path)
  131. default_storage.save(group_avatar_path, group_avatar)
  132. group.group_avatar = group_avatar_path
  133. group.save()
  134. # Redis 群组数据缓存更新
  135. group_info = set_group_info(group)
  136. return response(200, 'Update Group Success', u'群组更新成功', {
  137. 'group_id': group_id,
  138. 'group': group_info,
  139. 'users': get_group_users_info(group_id, admin_id),
  140. })
  141. @logit
  142. def group_list_api(request):
  143. """
  144. 群组列表
  145. :param request:
  146. :return:
  147. """
  148. user_id = request.POST.get('user_id', '')
  149. page = int(request.POST.get('page', 1))
  150. num = int(request.POST.get('num', settings.GROUP_PER_PAGE))
  151. group_users = GroupUserInfo.objects.filter(user_id=user_id, user_status=GroupUserInfo.PASSED).order_by('-pk')
  152. group_users, left = pagination(group_users, page, num)
  153. groups = []
  154. for group_user in group_users:
  155. group_info = get_group_info(group_user.group_id)
  156. groups.append(group_info) if group_info else None
  157. return response(200, 'Get Group List Success', u'获取群组列表成功', {
  158. 'groups': groups,
  159. 'left': left,
  160. })
  161. @logit
  162. def group_join_api(request):
  163. """
  164. 申请加群
  165. :param request:
  166. :return:
  167. """
  168. group_id = request.POST.get('group_id', '')
  169. user_id = request.POST.get('user_id', '')
  170. nickname = request.POST.get('nickname', '')
  171. # 用户校验
  172. try:
  173. user = UserInfo.objects.get(user_id=user_id)
  174. except UserInfo.DoesNotExist:
  175. return response(UserStatusCode.USER_NOT_FOUND)
  176. # 群组校验
  177. try:
  178. group = GroupInfo.objects.get(group_id=group_id)
  179. except GroupInfo.DoesNotExist:
  180. return response(GroupStatusCode.GROUP_NOT_FOUND)
  181. # 群组锁定校验
  182. if group.group_lock:
  183. return response(GroupStatusCode.GROUP_HAS_LOCKED)
  184. # 群组用户记录创建,若记录不存在,则创建,若记录已存在,则更新
  185. group_user, created = GroupUserInfo.objects.get_or_create(
  186. group_id=group_id,
  187. user_id=user_id,
  188. )
  189. if group_user.user_status != GroupUserInfo.PASSED:
  190. group_user.current_id = int(r.get(GROUP_LAST_PHOTO_PK % group_id) or -1)
  191. group_user.nickname = nickname or user.final_nickname
  192. group_user.avatar = user.avatar
  193. # group_user.admin = False # Admin Field Default False, Should Not Assign
  194. group_user.user_status = GroupUserInfo.PASSED
  195. group_user.passed_at = tc.utc_datetime()
  196. group_user.save()
  197. # Redis 群组用户数据缓存
  198. set_group_users_info(group)
  199. # Redis 群组通过集合缓存
  200. r.srem(GROUP_USERS_REFUSED_SET % group_id, user_id)
  201. r.srem(GROUP_USERS_DELETED_SET % group_id, user_id)
  202. r.srem(GROUP_USERS_QUIT_SET % group_id, user_id)
  203. r.sadd(GROUP_USERS_PASSED_SET % group_id, user_id)
  204. return response(200, 'Apply Success', u'申请成功', {
  205. 'current_id': group_user.current_id,
  206. 'photos': [],
  207. 'group_id': group_id,
  208. 'group': get_group_info(group_id),
  209. 'user_id': user_id,
  210. 'users': get_group_users_info(group_id, user_id),
  211. })
  212. @logit
  213. def group_lock_api(request):
  214. """
  215. 群组锁定
  216. :param request:
  217. :return:
  218. """
  219. group_id = request.POST.get('group_id', '')
  220. admin_id = request.POST.get('admin_id', '') or request.POST.get('user_id', '')
  221. # 群组校验
  222. try:
  223. group = GroupInfo.objects.get(group_id=group_id)
  224. except GroupInfo.DoesNotExist:
  225. return response(GroupStatusCode.GROUP_NOT_FOUND)
  226. # 权限校验
  227. if group.admin_id != admin_id:
  228. return response(GroupStatusCode.NO_LOCK_PERMISSION)
  229. # 群组锁定
  230. group.group_lock = True
  231. group.save()
  232. # Redis 群组数据缓存更新
  233. set_group_info(group)
  234. return response(200, 'Lock Success', u'锁定成功')
  235. @logit
  236. def group_unlock_api(request):
  237. """
  238. 群组解锁
  239. :param request:
  240. :return:
  241. """
  242. group_id = request.POST.get('group_id', '')
  243. admin_id = request.POST.get('admin_id', '') or request.POST.get('user_id', '')
  244. # 群组校验
  245. try:
  246. group = GroupInfo.objects.get(group_id=group_id)
  247. except GroupInfo.DoesNotExist:
  248. return response(GroupStatusCode.GROUP_NOT_FOUND)
  249. # 权限校验
  250. if group.admin_id != admin_id:
  251. return response(GroupStatusCode.NO_UNLOCK_PERMISSION)
  252. # 群组解锁
  253. group.group_lock = False
  254. group.save()
  255. # Redis 群组数据缓存更新
  256. set_group_info(group)
  257. return response(200, u'Unlock Success', u'解锁成功')
  258. @logit
  259. def group_remove_api(request):
  260. """
  261. 成员移除
  262. :param request:
  263. :return:
  264. """
  265. group_id = request.POST.get('group_id', '')
  266. admin_id = request.POST.get('admin_id', '')
  267. user_id = request.POST.get('user_id', '')
  268. # 群组校验
  269. try:
  270. group = GroupInfo.objects.get(group_id=group_id)
  271. except GroupInfo.DoesNotExist:
  272. return response(GroupStatusCode.GROUP_NOT_FOUND)
  273. # 权限校验
  274. if group.admin_id != admin_id or group.admin_id == user_id: # 管理员也不允许将自己移除
  275. return response(GroupStatusCode.NO_REMOVE_PERMISSION)
  276. # 群组用户校验
  277. try:
  278. group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.PASSED)
  279. except GroupUserInfo.DoesNotExist:
  280. return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND)
  281. # 群组用户移除
  282. group_user.user_status = GroupUserInfo.DELETED
  283. group_user.deleted_at = tc.utc_datetime()
  284. group_user.save()
  285. # Redis 群组数据缓存更新
  286. group_users = set_group_users_info(group)
  287. # Redis 群组删除集合缓存
  288. r.srem(GROUP_USERS_PASSED_SET % group_id, user_id)
  289. r.sadd(GROUP_USERS_DELETED_SET % group_id, user_id)
  290. return response(200, 'Remove Success', u'用户移除成功', {
  291. 'group_id': group_id,
  292. 'users': group_users,
  293. })
  294. @logit
  295. def group_quit_api(request):
  296. """
  297. 成员退出
  298. :param request:
  299. :return:
  300. """
  301. group_id = request.POST.get('group_id', '')
  302. user_id = request.POST.get('user_id', '')
  303. # 群组校验
  304. try:
  305. group = GroupInfo.objects.get(group_id=group_id)
  306. except GroupInfo.DoesNotExist:
  307. return response(GroupStatusCode.GROUP_NOT_FOUND)
  308. # 权限校验
  309. if group.admin_id == user_id: # 管理员也不允许自己退出
  310. return response(GroupStatusCode.NO_QUIT_PERMISSION)
  311. # 群组用户校验
  312. try:
  313. group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.PASSED)
  314. except GroupUserInfo.DoesNotExist:
  315. return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND)
  316. # 群组用户移除
  317. group_user.user_status = GroupUserInfo.QUIT
  318. group_user.quit_at = tc.utc_datetime()
  319. group_user.save()
  320. # Redis 群组数据缓存更新
  321. group_users = set_group_users_info(group)
  322. # Redis 群组删除集合缓存
  323. r.srem(GROUP_USERS_PASSED_SET % group_id, user_id)
  324. r.sadd(GROUP_USERS_QUIT_SET % group_id, user_id)
  325. return response(200, 'Quit Success', u'用户退出成功', {
  326. 'group_id': group_id,
  327. 'users': group_users,
  328. })
  329. @logit
  330. def group_pass_api(request):
  331. """
  332. 申请通过
  333. :param request:
  334. :return:
  335. """
  336. group_id = request.POST.get('group_id', '')
  337. admin_id = request.POST.get('admin_id', '')
  338. user_id = request.POST.get('user_id', '')
  339. # 群组校验
  340. try:
  341. group = GroupInfo.objects.get(group_id=group_id)
  342. except GroupInfo.DoesNotExist:
  343. return response(GroupStatusCode.GROUP_NOT_FOUND)
  344. # 权限校验
  345. if group.admin_id != admin_id:
  346. return response(GroupStatusCode.NO_PASS_PERMISSION)
  347. # 群组用户校验
  348. try:
  349. group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.APPLYING)
  350. except GroupUserInfo.DoesNotExist:
  351. return response(GroupStatusCode.JOIN_REQUEST_NOT_FOUND)
  352. # 群组用户通过
  353. group_user.user_status = GroupUserInfo.PASSED
  354. group_user.passed_at = tc.utc_datetime()
  355. group_user.save()
  356. # Redis 群组数据缓存更新
  357. group_users = set_group_users_info(group)
  358. # Redis 群组通过集合缓存
  359. r.srem(GROUP_USERS_APPLYING_SET % group_id, user_id)
  360. r.sadd(GROUP_USERS_PASSED_SET % group_id, user_id)
  361. return response(200, 'Pass Success', u'申请通过成功', {
  362. 'group_id': group_id,
  363. 'users': group_users,
  364. })
  365. @logit
  366. def group_refuse_api(request):
  367. """
  368. 申请拒绝
  369. :param request:
  370. :return:
  371. """
  372. group_id = request.POST.get('group_id', '')
  373. admin_id = request.POST.get('admin_id', '')
  374. user_id = request.POST.get('user_id', '')
  375. # 群组校验
  376. try:
  377. group = GroupInfo.objects.get(group_id=group_id)
  378. except GroupInfo.DoesNotExist:
  379. return response(GroupStatusCode.GROUP_NOT_FOUND)
  380. # 权限校验
  381. if group.admin_id != admin_id:
  382. return response(GroupStatusCode.NO_REFUSE_PERMISSION)
  383. # 群组用户校验
  384. try:
  385. group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.APPLYING)
  386. except GroupUserInfo.DoesNotExist:
  387. return response(GroupStatusCode.JOIN_REQUEST_NOT_FOUND)
  388. # 群组用户拒绝
  389. group_user.user_status = GroupUserInfo.REFUSED
  390. group_user.refused_at = tc.utc_datetime()
  391. group_user.save()
  392. # Redis 群组数据缓存更新
  393. group_users = set_group_users_info(group)
  394. # Redis 群组拒绝集合缓存
  395. r.srem(GROUP_USERS_APPLYING_SET % group_id, user_id)
  396. r.sadd(GROUP_USERS_REFUSED_SET % group_id, user_id)
  397. return response(200, 'Refuse Success', u'申请拒绝成功', {
  398. 'group_id': group_id,
  399. 'users': group_users,
  400. })
  401. @logit
  402. def group_data_api(request):
  403. """
  404. 群组数据, 评论数, 点赞数
  405. :param request:
  406. :return:
  407. """
  408. group_id = request.POST.get('group_id', '')
  409. return response(200, 'Get Group Data Success', u'获取群组数据成功', {
  410. 'photo_datas': get_group_photo_data(group_id),
  411. })
  412. @logit
  413. def flyimg_upload_api(request):
  414. """
  415. 飞图上传/飞图列表
  416. :param request:
  417. :return:
  418. """
  419. group_id = request.POST.get('group_id', '')
  420. user_id = request.POST.get('user_id', '')
  421. nickname = request.POST.get('nickname', '')
  422. photo = request.FILES.get('photo', '')
  423. current_id = int(request.POST.get('current_id', -1))
  424. # 用户校验
  425. try:
  426. user = UserInfo.objects.get(user_id=user_id)
  427. except UserInfo.DoesNotExist:
  428. return response(UserStatusCode.USER_NOT_FOUND)
  429. # 群组用户校验
  430. try:
  431. group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.PASSED)
  432. except GroupUserInfo.DoesNotExist:
  433. return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND)
  434. if photo:
  435. photo_path = 'fly/{uuid}{extension}'.format(uuid=shortuuid.uuid(), extension=os.path.splitext(photo.name)[1] or 'jpeg')
  436. photo_thumbnail_path = photo_path.replace('.', '_thumbnail.')
  437. photo_thumbnail2_path = photo_path.replace('.', '_thumbnail2.')
  438. if default_storage.exists(photo_path):
  439. default_storage.delete(photo_path)
  440. default_storage.save(photo_path, photo)
  441. # if default_storage.exists(photo_thumbnail_path):
  442. # default_storage.delete(photo_thumbnail_path)
  443. # default_storage.save(photo_thumbnail_path, photo)
  444. # 群组照片缩略图生成
  445. # 双列: 540, 40-50K
  446. photo_w, photo_h, photo_thumbnail_w, photo_thumbnail_h = make_thumbnail(
  447. os.path.join(settings.MEDIA_ROOT, photo_path).replace('\\', '/'),
  448. os.path.join(settings.MEDIA_ROOT, photo_thumbnail_path).replace('\\', '/'),
  449. settings.THUMBNAIL_MAX_WIDTH
  450. )
  451. # 单列: 1080, xx-100K
  452. photo_w, photo_h, photo_thumbnail2_w, photo_thumbnail2_h = make_thumbnail(
  453. os.path.join(settings.MEDIA_ROOT, photo_path).replace('\\', '/'),
  454. os.path.join(settings.MEDIA_ROOT, photo_thumbnail2_path).replace('\\', '/'),
  455. settings.THUMBNAIL_MAX_WIDTH2
  456. )
  457. # 群组照片记录创建
  458. group_photo = GroupPhotoInfo.objects.create(
  459. group_id=group_id,
  460. user_id=user_id,
  461. nickname=nickname or user.final_nickname,
  462. avatar=user.avatar,
  463. photo_path=photo_path,
  464. photo_w=photo_w,
  465. photo_h=photo_h,
  466. photo_thumbnail_path=photo_thumbnail_path,
  467. photo_thumbnail_w=photo_thumbnail_w,
  468. photo_thumbnail_h=photo_thumbnail_h,
  469. photo_thumbnail2_path=photo_thumbnail2_path,
  470. photo_thumbnail2_w=photo_thumbnail2_w,
  471. photo_thumbnail2_h=photo_thumbnail2_h,
  472. )
  473. # 设置群组最后一张照片PK
  474. r.set(GROUP_LAST_PHOTO_PK % group_id, group_photo.pk)
  475. # 获取从 current_id 到 now 的群组照片列表
  476. group_photos = GroupPhotoInfo.objects.filter(
  477. group_id=group_id,
  478. status=True,
  479. pk__gt=max(current_id, group_user.current_id),
  480. ).order_by(
  481. '-pk'
  482. )
  483. latest_photo = group_photos.first()
  484. return response(200, 'Flyimg Upload Success', u'飞图上传成功', {
  485. 'current_id': latest_photo and latest_photo.pk or current_id,
  486. 'photos': [photo.photo_info(user_id) for photo in group_photos],
  487. })
  488. @logit
  489. def comment_submit_api(request):
  490. """
  491. 飞图评论提交/飞图评论列表
  492. :param request:
  493. :return:
  494. """
  495. group_id = request.POST.get('group_id', '')
  496. user_id = request.POST.get('user_id', '')
  497. to_uid = request.POST.get('to_uid', '')
  498. photo_id = request.POST.get('photo_id', '')
  499. comment = request.POST.get('comment', '')
  500. # 群组用户校验
  501. try:
  502. group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.PASSED)
  503. except GroupUserInfo.DoesNotExist:
  504. return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND)
  505. # 群组照片校验
  506. try:
  507. group_photo = GroupPhotoInfo.objects.get(pk=photo_id)
  508. except GroupPhotoInfo.DoesNotExist:
  509. return response(GroupPhotoStatusCode.GROUP_PHOTO_NOT_FOUND)
  510. if comment:
  511. # 群组照片评论记录创建
  512. PhotoCommentInfo.objects.create(
  513. photo_id=photo_id,
  514. user_id=user_id,
  515. nickname=group_user.nickname,
  516. avatar=group_user.avatar,
  517. to_uid=to_uid,
  518. comment=comment,
  519. )
  520. # 群组照片评论数更新
  521. group_photo.comment_num += 1
  522. group_photo.save()
  523. # Redis 群组照片数据缓存
  524. set_group_photo_data(group_id)
  525. # Redis 群组照片评论列表缓存刷新
  526. set_group_photo_comment_list(photo_id)
  527. r.sadd(GROUP_PHOTO_WATCHER_SET % photo_id, user_id)
  528. # 判断群组照片发布者是否已经被管理员移除/主动退出,如若移除/退出,则不给发布者提醒
  529. # 照片所有者(评论/点赞)不给自己提醒
  530. if r.sismember(GROUP_USERS_PASSED_SET % group_photo.group_id, group_photo.user_id) and group_photo.user_id != user_id:
  531. UserMessageInfo.objects.create(
  532. from_uid=user_id,
  533. from_nickname=group_user.nickname,
  534. from_avatar=group_user.avatar,
  535. to_uid=group_photo.user_id,
  536. group_id=group_photo.group_id,
  537. photo_id=group_photo.pk,
  538. msg_type=UserMessageInfo.COMMENT,
  539. msg_title=u'评论',
  540. msg_content=comment,
  541. )
  542. # 给所有关注者(评论/点赞)发送提醒
  543. watchers = get_group_photo_watchers(photo_id)
  544. # 从关注者中移除该(评论/点赞)者
  545. watchers.discard(user_id)
  546. # 从关注者中移除该照片所有者
  547. watchers.discard(group_photo.user_id)
  548. for watcher in watchers:
  549. UserMessageInfo.objects.create(
  550. from_uid=user_id,
  551. from_nickname=group_user.nickname,
  552. from_avatar=group_user.avatar,
  553. to_uid=watcher,
  554. group_id=group_photo.group_id,
  555. photo_id=group_photo.pk,
  556. msg_type=UserMessageInfo.COMMENT,
  557. msg_title=u'评论',
  558. msg_content=comment,
  559. )
  560. return response(200, 'Comment Success', u'评论成功', {
  561. 'comments': get_group_photo_comment_list(photo_id),
  562. })
  563. @logit
  564. def thumbup_submit_api(request):
  565. """
  566. 飞图点赞提交
  567. :param request:
  568. :return:
  569. """
  570. group_id = request.POST.get('group_id', '')
  571. user_id = request.POST.get('user_id', '')
  572. photo_id = request.POST.get('photo_id', '')
  573. # 群组用户校验
  574. try:
  575. group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.PASSED)
  576. except GroupUserInfo.DoesNotExist:
  577. return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND)
  578. # 群组照片校验
  579. try:
  580. group_photo = GroupPhotoInfo.objects.get(pk=photo_id)
  581. except GroupPhotoInfo.DoesNotExist:
  582. return response(GroupPhotoStatusCode.GROUP_PHOTO_NOT_FOUND)
  583. # user_id 是否点赞 photo_id
  584. if get_group_photo_thumbup_flag(photo_id, user_id):
  585. return response(GroupPhotoStatusCode.DUPLICATE_THUMB_UP)
  586. # 群组照片点赞记录创建/更新
  587. photo_thumbup, created = PhotoThumbUpInfo.objects.get_or_create(
  588. photo_id=photo_id,
  589. user_id=user_id,
  590. )
  591. photo_thumbup.nickname = group_user.nickname
  592. photo_thumbup.avatar = group_user.avatar
  593. photo_thumbup.thumbup = True
  594. photo_thumbup.save()
  595. # Redis 群组照片点赞数据缓存
  596. set_group_photo_thumbup_flag(photo_id, user_id)
  597. # 群组照片点赞数更新
  598. group_photo.thumbup_num += 1
  599. group_photo.save()
  600. # Redis 群组照片数据缓存
  601. set_group_photo_data(group_id)
  602. # Redis 群组照片点赞列表缓存刷新
  603. set_group_photo_thumbup_list(photo_id)
  604. r.sadd(GROUP_PHOTO_WATCHER_SET % photo_id, user_id)
  605. # 判断群组照片发布者是否已经被管理员移除/主动退出,如若移除/退出,则不给发布者提醒
  606. # 照片所有者(评论/点赞)不给自己提醒
  607. if r.sismember(GROUP_USERS_PASSED_SET % group_photo.group_id, group_photo.user_id) and group_photo.user_id != user_id:
  608. UserMessageInfo.objects.create(
  609. from_uid=user_id,
  610. from_nickname=group_user.nickname,
  611. from_avatar=group_user.avatar,
  612. to_uid=group_photo.user_id,
  613. group_id=group_photo.group_id,
  614. photo_id=group_photo.pk,
  615. msg_type=UserMessageInfo.THUMBUP,
  616. msg_title=u'点赞',
  617. msg_content=u'点赞',
  618. )
  619. # 给所有关注者(评论/点赞)发送提醒
  620. watchers = get_group_photo_watchers(photo_id)
  621. # 从关注者中移除该(评论/点赞)者
  622. watchers.discard(user_id)
  623. # 从关注者中移除该照片所有者
  624. watchers.discard(group_photo.user_id)
  625. for watcher in watchers:
  626. UserMessageInfo.objects.create(
  627. from_uid=user_id,
  628. from_nickname=group_user.nickname,
  629. from_avatar=group_user.avatar,
  630. to_uid=watcher,
  631. group_id=group_photo.group_id,
  632. photo_id=group_photo.pk,
  633. msg_type=UserMessageInfo.THUMBUP,
  634. msg_title=u'点赞',
  635. msg_content=u'点赞',
  636. )
  637. return response(200, 'Thumbup Success', u'点赞提交成功', {
  638. 'thumbup': True,
  639. 'thumbups': get_group_photo_thumbup_list(photo_id),
  640. })
  641. @logit
  642. def thumbup_list_api(request):
  643. """
  644. 飞图点赞列表
  645. :param request:
  646. :return:
  647. """
  648. group_id = request.POST.get('group_id', '')
  649. user_id = request.POST.get('user_id', '')
  650. photo_id = request.POST.get('photo_id', '')
  651. return response(200, 'Get Thumbup List Success', u'获取点赞列表成功', {
  652. 'thumbup': get_group_photo_thumbup_flag(photo_id, user_id), # user_id 是否点赞 photo_id
  653. 'thumbups': get_group_photo_thumbup_list(photo_id), # 群组照片点赞列表
  654. })
  655. @logit
  656. def thumbup_cancel_api(request):
  657. """
  658. 飞图点赞取消
  659. :param request:
  660. :return:
  661. """
  662. group_id = request.POST.get('group_id', '')
  663. user_id = request.POST.get('user_id', '')
  664. photo_id = request.POST.get('photo_id', '')
  665. # 群组用户校验
  666. try:
  667. group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.PASSED)
  668. except GroupUserInfo.DoesNotExist:
  669. return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND)
  670. # 群组照片校验
  671. try:
  672. group_photo = GroupPhotoInfo.objects.get(pk=photo_id)
  673. except GroupPhotoInfo.DoesNotExist:
  674. return response(GroupPhotoStatusCode.GROUP_PHOTO_NOT_FOUND)
  675. # user_id 是否点赞 photo_id
  676. if not get_group_photo_thumbup_flag(photo_id, user_id):
  677. return response(GroupPhotoStatusCode.THUMB_UP_NOT_FOUND)
  678. # 群组照片点赞取消
  679. photo_thumbup, created = PhotoThumbUpInfo.objects.get_or_create(
  680. photo_id=photo_id,
  681. user_id=user_id,
  682. )
  683. photo_thumbup.thumbup = False
  684. photo_thumbup.save()
  685. # Redis 群组照片点赞数据移除
  686. del_group_photo_thumbup_flag(photo_id, user_id)
  687. # 群组照片点赞数更新
  688. group_photo.thumbup_num -= 1
  689. group_photo.save()
  690. # Redis 群组照片数据缓存
  691. set_group_photo_data(group_id)
  692. # Redis 群组照片点赞列表缓存刷新
  693. set_group_photo_thumbup_list(photo_id)
  694. # 判断群组照片发布者是否已经被管理员移除/主动退出,如若移除/退出,则不给发布者提醒
  695. if r.sismember(GROUP_USERS_PASSED_SET % group_photo.group_id, group_photo.user_id):
  696. UserMessageInfo.objects.create(
  697. from_uid=user_id,
  698. from_nickname=group_user.nickname,
  699. from_avatar=group_user.avatar,
  700. to_uid=group_photo.user_id,
  701. group_id=group_photo.group_id,
  702. photo_id=group_photo.pk,
  703. msg_type=UserMessageInfo.THUMBUP,
  704. msg_title=u'取消点赞',
  705. msg_content=u'取消点赞',
  706. )
  707. # 群组照片点赞列表
  708. photo_thumbups = PhotoThumbUpInfo.objects.filter(
  709. photo_id=photo_id,
  710. thumbup=True,
  711. )
  712. return response(200, 'Thumbup Cancel Success', u'点赞取消成功', {
  713. 'thumbup': False,
  714. 'thumbups': [thumbup.thumbup_info for thumbup in photo_thumbups],
  715. })
  716. @logit
  717. def pai2_home_api(request):
  718. """
  719. 首页信息
  720. :param request:
  721. :return:
  722. """
  723. user_id = request.POST.get('user_id', '')
  724. page = int(request.POST.get('page', 1))
  725. num = int(request.POST.get('num', settings.PAI2_HOME_PER_PAGE))
  726. # 执行原生 SQL 语句,获取首页照片列表
  727. cursor = connection.cursor()
  728. cursor.execute(PAI2_HOME_API.format(
  729. user_id=user_id,
  730. offset=0,
  731. rows=settings.PAI2_HOME_MAX_ROWS,
  732. ))
  733. rows = cursor.fetchall()
  734. # 使用 records 执行原生 SQL 语句,获取首页照片列表
  735. # rows = db.query(PAI2_HOME_API.format(
  736. # user_id=user_id,
  737. # offset=0,
  738. # rows=settings.PAI2_HOME_MAX_ROWS,
  739. # )).all()
  740. # 首页照片分页
  741. rows, left = pagination(rows, page, num)
  742. # 首页照片信息
  743. rows = [{
  744. 'group_id': row[0],
  745. 'group_name': row[1],
  746. 'group_default_avatar': row[2],
  747. 'group_avatar': row[3],
  748. 'group_from': row[4],
  749. 'photo_id': row[5],
  750. 'photo_url': img_url(row[6]),
  751. 'photo_w': row[7],
  752. 'photo_h': row[8],
  753. 'photo_thumbnail_url': img_url(row[9]),
  754. 'photo_thumbnail_w': row[10],
  755. 'photo_thumbnail_h': row[11],
  756. 'photo_thumbnail2_url': img_url(row[12]),
  757. 'photo_thumbnail2_w': row[13],
  758. 'photo_thumbnail2_h': row[14],
  759. 'photo_share_url': share_url(row[5]), # Warning: Index of This Line is 5
  760. 'user_id': row[15],
  761. 'nickname': row[16],
  762. 'avatar': row[17],
  763. 'comment_num': row[18],
  764. 'thumbup_num': row[19],
  765. 'photo_from': row[20],
  766. 'created_at': row[21],
  767. 'origin_expired_stamps': origin_expired_stamps(row[22], row[15]),
  768. 'thumbup': get_group_photo_thumbup_flag(row[5], user_id),
  769. 'porder': get_lensman_order_record(row[5], user_id) if row[20] == GroupPhotoInfo.SESSION_GROUP else {},
  770. } for row in rows]
  771. # rows = [dict(row) for row in rows]
  772. # [row.update({
  773. # 'photo_url': img_url(row['photo_path']),
  774. # 'photo_thumbnail_url': img_url(row['photo_thumbnail_path']),
  775. # 'photo_thumbnail2_url': img_url(row['photo_thumbnail2_path']),
  776. # 'photo_share_url': share_url(row['photo_id']),
  777. # 'thumbup': get_group_photo_thumbup_flag(row['photo_id'], user_id),
  778. # 'porder': get_lensman_order_record(row['photo_id'], user_id) if row['photo_from'] == GroupPhotoInfo.SESSION_GROUP else {},
  779. # }) for row in rows]
  780. return response(200, 'Get Home Data Success', u'获取首页数据成功', {
  781. 'photos': rows,
  782. 'left': left,
  783. })
  784. @logit
  785. def lensman_photo_price(request):
  786. """
  787. 摄影师照片价格获取
  788. :param request:
  789. :return:
  790. """
  791. user_id = request.POST.get('user_id', '')
  792. photo_id = request.POST.get('photo_id', '')
  793. photo_type = request.POST.get('photo_type', 'nomark') # nomark for 去除水印, origin for 获取高清图
  794. lensman_photo_price_key = LENSMAN_PHOTO_PRICE % (user_id, photo_id, photo_type)
  795. # Redis 获取存储的价格
  796. price = int(r.get(lensman_photo_price_key) or 0)
  797. if price:
  798. # Redis 获取存储的砍价次数
  799. haggle_times = r.incr(LENSMAN_PHOTO_HAGGLE_TIMES % (user_id, photo_id, photo_type))
  800. # 判断砍价是否已经超过次数
  801. if haggle_times <= settings.LENSMAN_PHOTO_HAGGLE_MAX_TIMES:
  802. # 砍掉的价格
  803. haggle_price = random.choice([50, 100])
  804. # 砍价后的价格
  805. price = max(price - haggle_price, 1)
  806. # Redis 设置新价格
  807. r.set(lensman_photo_price_key, price)
  808. else:
  809. try:
  810. group_photo = GroupPhotoInfo.objects.get(pk=photo_id)
  811. except GroupPhotoInfo.DoesNotExist:
  812. return response(GroupPhotoStatusCode.GROUP_PHOTO_NOT_FOUND)
  813. # 获取摄影师定价
  814. price = get_lensman_price_fixed(group_photo.user_id).get(photo_type, 999)
  815. # Redis 设置新价格
  816. r.set(lensman_photo_price_key, price)
  817. return response(200, 'Get Price Success', u'获取价格成功', {
  818. 'price': price
  819. })
  820. @logit
  821. def lensman_photo_bought(request):
  822. """
  823. 摄影师照片已购买
  824. :param request:
  825. :return:
  826. """
  827. user_id = request.POST.get('user_id', '')
  828. photo_id = request.POST.get('photo_id', '')
  829. return response(200, 'Get Bought Data Success', u'获取购买数据成功', {
  830. 'porder': get_lensman_order_record(photo_id, user_id)
  831. })
  832. @logit
  833. def group_photo_detail(request, photo_id):
  834. photo = GroupPhotoInfo.objects.get(pk=photo_id)
  835. return render(request, 'photo/photo_detail.html', {'photo_url': photo.photo_url, 'api_domain': settings.API_DOMAIN})
  836. @logit
  837. def group_detail(request, group_id):
  838. return render(request, 'page/{}_download.html'.format('ios' if request.iOS else 'adr'), {})
  839. class GroupInfoViewSet(viewsets.ModelViewSet):
  840. queryset = GroupInfo.objects.all().order_by('-pk')
  841. serializer_class = GroupInfoSerializer
  842. class GroupUserInfoViewSet(viewsets.ModelViewSet):
  843. queryset = GroupUserInfo.objects.all().order_by('-pk')
  844. serializer_class = GroupUserInfoSerializer
  845. class GroupPhotoInfoViewSet(viewsets.ModelViewSet):
  846. queryset = GroupPhotoInfo.objects.all().order_by('-pk')
  847. serializer_class = GroupPhotoInfoSerializer
  848. # Only Once Function
  849. def refresh_thumbnail():
  850. """ 刷新缩略图 """
  851. photos = GroupPhotoInfo.objects.filter(status=True)
  852. for photo in photos:
  853. try:
  854. photo_path = photo.photo_path
  855. photo_thumbnail_path = photo_path.replace('.', '_thumbnail.')
  856. photo_thumbnail2_path = photo_path.replace('.', '_thumbnail2.')
  857. # 群组照片缩略图生成
  858. # 双列: 540, 40-50K
  859. photo_w, photo_h, photo_thumbnail_w, photo_thumbnail_h = make_thumbnail(
  860. os.path.join(settings.MEDIA_ROOT, photo_path).replace('\\', '/'),
  861. os.path.join(settings.MEDIA_ROOT, photo_thumbnail_path).replace('\\', '/'),
  862. settings.THUMBNAIL_MAX_WIDTH
  863. )
  864. # 单列: 1080, xx-100K
  865. photo_w, photo_h, photo_thumbnail2_w, photo_thumbnail2_h = make_thumbnail(
  866. os.path.join(settings.MEDIA_ROOT, photo_path).replace('\\', '/'),
  867. os.path.join(settings.MEDIA_ROOT, photo_thumbnail2_path).replace('\\', '/'),
  868. settings.THUMBNAIL_MAX_WIDTH2
  869. )
  870. photo.photo_w = photo_w
  871. photo.photo_h = photo_h
  872. photo.photo_thumbnail_path = photo_thumbnail_path
  873. photo.photo_thumbnail_w = photo_thumbnail_w
  874. photo.photo_thumbnail_h = photo_thumbnail_h
  875. photo.photo_thumbnail2_path = photo_thumbnail2_path
  876. photo.photo_thumbnail2_w = photo_thumbnail2_w
  877. photo.photo_thumbnail2_h = photo_thumbnail2_h
  878. photo.save()
  879. except Exception as e:
  880. pass
  881. return 'Refresh Thumbnail OK'
  882. def statistic_thumbnail_size(pfrom):
  883. """
  884. 统计缩略图大小
  885. :param pfrom: 0 for APP_GROUP, 1 for SESSION_GROUP, -1 for ALL
  886. :return:
  887. """
  888. if pfrom == -1:
  889. photos = GroupPhotoInfo.objects.filter(status=True)
  890. else:
  891. photos = GroupPhotoInfo.objects.filter(photo_from=pfrom, status=True)
  892. photo_count = photos.count()
  893. photo_size = 0
  894. photo_thumbnail_size = 0
  895. photo_thumbnail2_size = 0
  896. for photo in photos:
  897. photo_size += os.path.getsize(os.path.join(settings.MEDIA_ROOT, photo.photo_path).replace('\\', '/'))
  898. photo_thumbnail_size += os.path.getsize(os.path.join(settings.MEDIA_ROOT, photo.photo_thumbnail_path).replace('\\', '/'))
  899. photo_thumbnail2_size += os.path.getsize(os.path.join(settings.MEDIA_ROOT, photo.photo_thumbnail2_path).replace('\\', '/'))
  900. print '>>> Photo Size: %.3f KB' % (photo_size / 1024 / photo_count)
  901. print '>>> Photo Thumbnail Size: %.3f KB' % (photo_thumbnail_size / 1024 / photo_count)
  902. print '>>> Photo Thumbnail2 Size: %.3f KB' % (photo_thumbnail2_size / 1024 / photo_count)
  903. return 'Statistic Thumbnail Size OK'