Last active
December 2, 2018 07:10
-
-
Save noimin0610/3784eefdc9de0bf35cd29ada6c879ad0 to your computer and use it in GitHub Desktop.
AtCoder Performances ソースコード (一部)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.shortcuts import render | |
from django.views.generic import FormView | |
from .utils.error_reporter import report_error_if_violates as report_vio | |
from .utils.atcoder_history import AtCoderUserHistory, AtCoderUserHistoryStatistics | |
from .utils.atcoder_figure import AtCoderFigure | |
from .utils.base64_graph import base64_png | |
from .forms import UserNamesForm | |
from atcoderapps.settings import SOCIAL_AUTH_TWITTER_KEY, SOCIAL_AUTH_TWITTER_SECRET | |
from django.contrib.auth.decorators import login_required | |
from social_django.models import UserSocialAuth | |
import json | |
import base64 | |
from requests_oauthlib import OAuth1Session | |
import os, os.path | |
MAX_RIVAL_NUM = 4 | |
MEDIA_URL = "https://upload.twitter.com/1.1/media/upload.json" | |
TWEET_URL = "https://api.twitter.com/1.1/statuses/update.json" | |
class IndexView(FormView): | |
template_name = "atcoderperformances/index.html" | |
form_class = UserNamesForm | |
def get_form(self): | |
form = super(IndexView, self).get_form() | |
form.set_attr("username", { | |
"tabindex": 1, | |
"class": "form-control", | |
"placeholder": "ex. Noimin" | |
}) | |
form.set_attr("rivalname", { | |
"tabindex": 2, | |
"class": "form-control", | |
"placeholder": "ex. Noimin,fuurin" | |
}) | |
return form | |
class ShowGraphView(FormView): | |
template_name = "atcoderperformances/show_graph.html" | |
form_class = UserNamesForm | |
def parse_rivals(self, cs_rivalnames): | |
rivals = list(set(cs_rivalnames.replace(" ", "").split(","))) | |
if "" in rivals: rivals.remove("") | |
return rivals | |
def check_rivals_num(self, rivals): | |
violates = len(rivals) > MAX_RIVAL_NUM | |
msg = "Number of rivals is up to <strong>{}</strong>.".format(MAX_RIVAL_NUM) | |
report_vio(self.request, violates, msg) | |
return not violates | |
def check_all_hist_existenses(self, hists): | |
not_found_usernames = [hist.name for hist in hists if not hist.exists] | |
violates = len(not_found_usernames) > 0 | |
msg = "Histories of <strong>{}</strong> could not be found.".format(", ".join(not_found_usernames)) | |
report_vio(self.request, violates, msg) | |
def check_time_cross_over(self, since, until): | |
violates = since > until | |
msg = "Since cannot be after Until." | |
report_vio(self.request, violates, msg) | |
def get_form(self): | |
form = super(ShowGraphView, self).get_form() | |
form.set_attr("username", { | |
"value": self.username, | |
"tabindex": 1, | |
"class": "form-control", | |
"placeholder": "ex. Noimin" | |
}) | |
form.set_attr("rivalname", { | |
"value": self.rivalname, | |
"tabindex": 2, | |
"class": "form-control", | |
"placeholder": "ex. Noimin,fuurin" | |
}) | |
return form | |
def get_context_data(self, **kwargs): | |
if 'params' in self.request.GET: | |
params = self.request.GET.get('params').split('_') | |
username = self.username = params[0] | |
rivalname = self.rivalname = params[1] | |
since = params[2] | |
until = params[3] | |
else: | |
username = self.username = self.request.GET.get("username") | |
rivalname = self.rivalname = self.request.GET.get("rivalname") | |
since = self.request.GET.get('since') | |
until = self.request.GET.get('until') | |
if username == None: username = self.username = "" | |
if rivalname == None: rivalname = self.rivalname = "" | |
context = super().get_context_data(**kwargs) | |
context['username'], context['rivalname'] = username, rivalname | |
rivalnames = self.parse_rivals(rivalname) | |
if not self.check_rivals_num(rivalnames): rivalnames = [] | |
hists = [AtCoderUserHistory(name) for name in [username] + rivalnames if name != ""] | |
self.check_all_hist_existenses(hists) | |
statistics = AtCoderUserHistoryStatistics(hists) | |
context['atcoder_times'] = [str(time.date()) for time in statistics.times()] | |
if context['atcoder_times']: | |
if since: | |
context['since'] = since | |
hists = [hist.since(since) for hist in hists] | |
else: | |
context['since'] = context['atcoder_times'][0] | |
if until: | |
context['until'] = until | |
hists = [hist.until(until) for hist in hists] | |
else: | |
context['until'] = context['atcoder_times'][-1] | |
if since and until: self.check_time_cross_over(since, until) | |
statistics = AtCoderUserHistoryStatistics(hists) | |
context['figure'] = base64_png(AtCoderFigure(hists).make_performances_figure()) | |
context['atcoder_statistics'] = statistics().round(2) | |
try: | |
user = UserSocialAuth.objects.get(user_id=self.request.user.id) | |
except: | |
context['user'] = None | |
else: | |
context['user'] = user | |
if 'tweet' in self.request.GET: | |
tweet_url = self.tweet(context) | |
violates = (tweet_url == None) | |
if violates: | |
msg = "Tweet failed." | |
report_vio(self.request, violates, msg) | |
else: | |
context['tweet_url'] = tweet_url | |
return context | |
def tweet(self, context): | |
# セッション開始 | |
user = context['user'] | |
session = OAuth1Session( | |
SOCIAL_AUTH_TWITTER_KEY, | |
SOCIAL_AUTH_TWITTER_SECRET, | |
user.access_token['oauth_token'], | |
user.access_token['oauth_token_secret'] | |
) | |
# ローカルに画像を保存 | |
figure = context['figure'] | |
file_path = "{}/{}_{}_{}_{}.png".format( | |
os.path.join( | |
os.path.dirname(__file__), | |
'tmp' | |
), | |
context['username'], | |
context['rivalname'], | |
context['since'], | |
context['until'] | |
) | |
with open(file_path, 'wb') as f: | |
f.write(base64.b64decode(figure)) | |
with open(file_path, 'rb') as f: | |
# 画像アップロード | |
files = {"media" : f} | |
media_request = session.post(MEDIA_URL, files=files) | |
if media_request.status_code != 200: | |
f.close() | |
os.remove(file_path) | |
return None | |
# 画像付きツイート | |
media_id = json.loads(media_request.text)['media_id'] | |
status = "Performances of {}{}{} ({}〜{}) https://atcoderapps.herokuapp.com/atcoderperformances/ #AtCoder_Performances".format( | |
context['username'], | |
", " if len(context['rivalname']) else " ", | |
", ".join(context['rivalname'].split(',')), | |
context['since'], | |
context['until'] | |
) | |
params = {'status': status, "media_ids": [media_id]} | |
tweet_request = session.post(TWEET_URL, params=params) | |
if tweet_request.status_code != 200: | |
f.close() | |
os.remove(file_path) | |
return None | |
os.remove(file_path) | |
tweet_url = json.loads(tweet_request.text)["entities"]["media"][0]["expanded_url"] | |
return tweet_url |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment