general.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. import seaborn
  2. from django.shortcuts import render, get_object_or_404
  3. from django.http import HttpResponseRedirect
  4. from django.urls import reverse
  5. from django.forms import modelformset_factory
  6. #from django.views import generic
  7. from django.contrib.auth.decorators import login_required, permission_required
  8. from website.settings import APPLICATION_NAME
  9. from rotbot.models import Network, Host, Channel, User, Message, Action, Notice, Join, Kick, CurseWord, Adjective
  10. from rotbot.forms import CurseWordForm, AdjectiveForm
  11. from rotbot.views.common import default_keywords, shorten_number, total_messages
  12. # Common
  13. def user_stats(name, event_stats, stats=False):
  14. if not stats:
  15. stats = {}
  16. if not event_stats:
  17. for stat in stats:
  18. stats[stat][name] = 0
  19. for stat in event_stats:
  20. if not stat.channel.name in stats:
  21. stats[stat.channel.name] = {}
  22. stats[stat.channel.name][name] = stat.amount
  23. return stats
  24. def index(request):
  25. networks = Network.objects.all()
  26. hosts = Host.objects.all()
  27. channels = Channel.objects.all()
  28. users = User.objects.all()
  29. joins = Join.objects.all()
  30. kicks = Kick.objects.all()
  31. messages = Message.objects.all()
  32. actions = Action.objects.all()
  33. notices = Notice.objects.all()
  34. cursewords = CurseWord.objects.all()
  35. context = {
  36. 'title': 'RotBot',
  37. 'icon': 'hashtag',
  38. 'description': 'Index of RotBot',
  39. 'keywords': default_keywords('index'),
  40. 'total_networks':shorten_number(networks.count()),
  41. 'total_hosts':shorten_number(hosts.count()),
  42. 'total_channels':shorten_number(channels.count()),
  43. 'total_users':shorten_number(users.count()),
  44. 'total_joins':shorten_number(joins.count()),
  45. 'total_kicks':shorten_number(kicks.count()),
  46. 'total_messages':shorten_number(messages.count()),
  47. 'total_actions':shorten_number(actions.count()),
  48. 'total_notices':shorten_number(notices.count()),
  49. 'total_cursewords':shorten_number(cursewords.count()),
  50. }
  51. return render(request, 'rotbot/index.html', context)
  52. def user(request, user_slug):
  53. user = get_object_or_404(User, slug=user_slug)
  54. network = Network.objects.get(id=user.network.id)
  55. messages = Message.objects.filter(user=user)
  56. actions = Action.objects.filter(user=user)
  57. notices = Notice.objects.filter(user=user)
  58. joins = Join.objects.filter(user=user)
  59. kicks = Kick.objects.filter(kicker=user)
  60. kicked = Kick.objects.filter(kicked=user)
  61. if user.last_event_type == 'pm':
  62. last_event_type = 'speaking privately'
  63. if user.last_event_type == 'pa':
  64. last_event_type = 'sending a private action'
  65. if user.last_event_type == 'pn':
  66. last_event_type = 'sending a private notice'
  67. if user.last_event_type == 'cm':
  68. last_event_type = 'speaking publicly'
  69. if user.last_event_type == 'ca':
  70. last_event_type = 'sending a public action'
  71. if user.last_event_type == 'cn':
  72. last_event_type = 'sending a public notice'
  73. if user.last_event_type == 'ct':
  74. last_event_type = 'changing the topic'
  75. if user.last_event_type == 'ck':
  76. last_event_type = 'changing the password'
  77. if user.last_event_type == 'ci':
  78. last_event_type = 'inviting'
  79. if user.last_event_type == 'cj':
  80. last_event_type = 'joining'
  81. if user.last_event_type == 'cp':
  82. last_event_type == 'parting'
  83. if user.last_event_type == 'ck':
  84. last_event_type = 'kicking'
  85. if user.last_event_type == 'kd':
  86. last_event_type = 'getting kicked'
  87. if user.last_event_type == 'mc':
  88. last_event_type = 'changing modes'
  89. if user.last_event_type == 'nc':
  90. last_event_type = 'nick change'
  91. if user.last_event_type =='sq':
  92. last_event_type = 'quitting'
  93. stats_dict = None
  94. stats_dict = user_stats('joins', joins, stats=stats_dict)
  95. stats_dict = user_stats('messages', messages, stats=stats_dict)
  96. stats_dict = user_stats('actions', actions, stats=stats_dict)
  97. stats_dict = user_stats('notices', notices, stats=stats_dict)
  98. stats_dict = user_stats('kicks', kicks, stats=stats_dict)
  99. stats_dict = user_stats('kicked', kicked, stats=stats_dict)
  100. labels = list(list(stats_dict.values())[0].keys())
  101. datasets = []
  102. dicts_amount = len(stats_dict)
  103. color_palette = seaborn.color_palette("husl", dicts_amount * 5)
  104. i = 0
  105. for color in color_palette:
  106. color_list = list(color)
  107. color_list[0] *= 255
  108. color_list[1] *= 255
  109. color_list[2] *= 255
  110. color_palette[i] = tuple(color_list)
  111. i += 1
  112. i = 0
  113. for dict in stats_dict:
  114. color_gradient = linear_gradient(color_palette[i], n=4)
  115. print(color_gradient)
  116. datasets.append({
  117. "label": dict,
  118. "data": list(stats_dict[dict].values()),
  119. "backgroundColor": 'rgba' + str(color_gradient[i]),#, 'rgba' + str(color_gradient[i]), 'rgba' + str(color_gradient[i]), 'rgba' + str(color_gradient[i]), 'rgba' + str(color_gradient[i]), 'rgba' + str(color_gradient[i]),],
  120. "borderColor": 'rgba' + str(color_gradient[i+1]),#, 'rgba' + str(color_gradient[i+1]), 'rgba' + str(color_gradient[i+1]), 'rgba' + str(color_gradient[i+1]), 'rgba' + str(color_gradient[i+1]), 'rgba' + str(color_gradient[i+1]),],
  121. #"pointBackgroundColor": ['rgba' + str(tuple(color_palette[i+1]))],
  122. #"pointBorderColor": ['rgba' + str(tuple(color_palette[i+3]))],
  123. #"pointStrokeColor": ['rgba' + str(tuple(color_palette[i+4]))],
  124. "hoverBackgroundColor": 'rgba' + str(color_palette[i+2]),#, 'rgba' + str(tuple(color_palette[i+2])), 'rgba' + str(tuple(color_palette[i+2])), 'rgba' + str(tuple(color_palette[i+2])), 'rgba' + str(tuple(color_palette[i+2])),],
  125. "hoverBorderColor": 'rgba' + str(color_palette[i+3]),#, 'rgba' + str(tuple(color_palette[i+3])), 'rgba' + str(tuple(color_palette[i+3])), 'rgba' + str(tuple(color_palette[i+3])), 'rgba' + str(tuple(color_palette[i+3])),],
  126. #"hoverWidth": 2,
  127. "borderWidth": 1,
  128. #"borderSkipped": False,
  129. })
  130. i += 1
  131. chart = {
  132. "type": "bar",
  133. "data": {
  134. "labels": labels,
  135. "datasets": datasets,
  136. },
  137. "options": {},
  138. }
  139. context = {
  140. 'parent_title': network.name,
  141. 'parent_url': reverse('rotbot:network', args=(network.slug,)),
  142. 'parent_icon': 'sitemap',
  143. 'title': user.name,
  144. 'icon': 'hashtag',
  145. 'description': 'Details of user %s on network %s' % (user.name, network.name),
  146. 'keywords': default_keywords() + '%s, %s' % (network.name, user.name),
  147. 'user': user,
  148. 'network': network,
  149. 'total_messages': shorten_number(total_messages(messages)),
  150. 'total_actions': shorten_number(total_messages(actions)),
  151. 'total_notices': shorten_number(total_messages(notices)),
  152. 'total_joins': shorten_number(joins.count()),
  153. 'total_kicks': shorten_number(kicked.count()),
  154. 'total_kicked': shorten_number(kicked.count()),
  155. 'last_event_type': last_event_type,
  156. 'stats': stats_dict,
  157. 'chart': chart,
  158. }
  159. return render(request, 'rotbot/user.html', context)
  160. def color_dict(gradient):
  161. ''' Takes in a list of RGB sub-lists and returns dictionary of
  162. colors in RGB and hex form for use in a graphing function
  163. defined later on '''
  164. gradients = []
  165. for RGB in gradient:
  166. gradients.append(tuple((RGB[0], RGB[1], RGB[2])))
  167. return tuple(gradients)
  168. # {
  169. # "r":[RGB[0] for RGB in gradient],
  170. # "g":[RGB[1] for RGB in gradient],
  171. # "b":[RGB[2] for RGB in gradient]}
  172. def linear_gradient(start_rgb, finish_hex="#FFFFFF", n=10):
  173. ''' returns a gradient list of (n) colors between
  174. two hex colors. start_hex and finish_hex
  175. should be the full six-digit color string,
  176. inlcuding the number sign ("#FFFFFF") '''
  177. # Starting and ending colors in RGB form
  178. #s = hex_to_RGB(start_hex)
  179. print(n)
  180. s = start_rgb
  181. f = hex_to_RGB(finish_hex)
  182. # Initilize a list of the output colors with the starting color
  183. RGB_list = [s]
  184. # Calcuate a color at each evenly spaced value of t from 1 to n
  185. for t in range(1, n):
  186. # Interpolate RGB vector for color at the current value of t
  187. curr_vector = [
  188. int(s[j] + (float(t)/(n-1))*(f[j]-s[j]))
  189. for j in range(3)
  190. ]
  191. # Add it to our list of output colors
  192. RGB_list.append(curr_vector)
  193. return color_dict(RGB_list)
  194. def hex_to_RGB(hex):
  195. ''' "#FFFFFF" -> [255,255,255] '''
  196. # Pass 16 to the integer function for change of base
  197. return [int(hex[i:i+2], 16) for i in range(1,6,2)]
  198. def RGB_to_hex(RGB):
  199. ''' [255,255,255] -> "#FFFFFF" '''
  200. # Components need to be integers for hex to make sense
  201. RGB = [int(x) for x in RGB]
  202. return "#"+"".join(["0{0:x}".format(v) if v < 16 else
  203. "{0:x}".format(v) for v in RGB])
  204. # from jchart import Chart
  205. # from jchart.config import DataSet
  206. #
  207. # class LineChart(Chart):
  208. #
  209. # chart_type = 'line'
  210. #
  211. # def get_datasets(self, channel_dict, **kwargs):
  212. # print(channel_dict)
  213. # data = []
  214. # for channel in channel_dict:
  215. # print(channel)
  216. # print(channel_dict[channel])
  217. # print(list(channel_dict[channel].values()))
  218. # print(channel_dict[channel].keys())
  219. # list(channel_dict[channel].values())
  220. # data.append(list(channel_dict[channel].values()))
  221. # print(data)
  222. #
  223. # a = DataSet(
  224. # data=data[0]
  225. # )
  226. # foobar = []
  227. # for d in data:
  228. # foobar.append(d)
  229. # return a
  230. # # [
  231. # # DataSet(
  232. # # data=data,
  233. # # #color=(55,55,55),
  234. # # )]
  235. # # [
  236. # # DataSet(
  237. # # data = [69, 30],
  238. # # #data = data
  239. # # color = (255,255,255)
  240. # # ),
  241. # # DataSet(
  242. # # data = [29, 70],
  243. # # #data = data
  244. # # color = (125,125,125)
  245. # # ),
  246. # # ]
  247. #
  248. # def get_labels(self, channel_dict, **kwargs):
  249. #
  250. # return ['Red', 'Blue']
  251. @login_required
  252. @permission_required('rotbot.add_curseword', raise_exception=True)
  253. def add_curseword(request):
  254. CurseWordFormSet = modelformset_factory(CurseWord, form=CurseWordForm, extra=4)
  255. AdjectiveFormSet = modelformset_factory(Adjective, form=AdjectiveForm, extra=4)
  256. if request.method == 'POST':
  257. curseword_formset = CurseWordFormSet(request.POST)
  258. Adjective_formset = AdjectiveFormSet(request.POST)
  259. if curseword_formset.is_valid() and Adjective_formset.is_valid():
  260. curseword_formset.save()
  261. Adjective_formset.save()
  262. return HttpResponseRedirect(reverse('rotbot:networks'))
  263. else:
  264. curseword_formset = CurseWordFormSet(queryset=CurseWord.objects.none())
  265. Adjective_formset = CurseWordFormSet(queryset=Adjective.objects.none())
  266. else: # Not a POST request.
  267. curseword_formset = CurseWordFormSet(queryset=CurseWord.objects.none())
  268. Adjective_formset = AdjectiveFormSet(queryset=Adjective.objects.none())
  269. context = {
  270. 'parent_title': 'RotBot',
  271. 'parent_url': reverse('rotbot:networks'),
  272. 'parent_icon': 'sitemap',
  273. 'title': 'Add curseword',
  274. 'icon': 'book dead',
  275. 'description': 'Add a curseword to RotBot\'s vocabulary.',
  276. 'keywords': default_keywords(),
  277. 'curseword_formset': curseword_formset,
  278. 'Adjective_formset': Adjective_formset,
  279. }
  280. return render(request, 'rotbot/add_curseword.html', context)