diff --git a/codedigger/lists/cron.py b/codedigger/lists/cron.py index 18da564..9666841 100644 --- a/codedigger/lists/cron.py +++ b/codedigger/lists/cron.py @@ -12,6 +12,7 @@ from codedigger.settings import EMAIL_HOST_USER from codeforces.api import user_status from user.exception import ValidationException +from .solved_update import UpdateforUserCodeforces def cron_codeforces(user): @@ -43,6 +44,11 @@ def cron_codeforces(user): continue +def cron_codeforces_all_users(limit): + for ele in User.objects.all(): + UpdateforUserCodeforces(ele, limit) + + def cron_uva(user): if user is None: return diff --git a/codedigger/lists/serializers.py b/codedigger/lists/serializers.py index e595c54..4bc325e 100644 --- a/codedigger/lists/serializers.py +++ b/codedigger/lists/serializers.py @@ -208,3 +208,10 @@ class EnrollInListSerializer(serializers.Serializer): class Meta: fields = ('slug', ) + + +class UpdateCodeforcesForUserSerializer(serializers.Serializer): + limit = serializers.IntegerField(required=False) + + class Meta: + fields = ('limit', ) \ No newline at end of file diff --git a/codedigger/lists/solved_update.py b/codedigger/lists/solved_update.py index c88ae09..d8d9237 100644 --- a/codedigger/lists/solved_update.py +++ b/codedigger/lists/solved_update.py @@ -149,3 +149,157 @@ def atcoder_scraper_check(user, prob): check = soup.find_all("span", {"class": "label label-success"}) if check: Solved.objects.create(user=user, problem=prob) + + +def UpdateforUserCodeforces(user, limit): + # limit should either be None, or be an integer greater than or equal to 1. + if user is None: + return (False, "Given User object cannot be None") + cf_handle = Profile.objects.get(owner=user).codeforces + if cf_handle == None: + return (False, "cf_handle cannot be None.") + try: + submission_user = user_status(cf_handle) + except ValidationException: + return (False, "Not able to fetch submission data from codeforces.") + for ele in submission_user: + if 'verdict' not in ele or 'contestId' not in ele or ele[ + 'verdict'] != 'OK': + continue + prob_id = str(ele['problem']['contestId']) + str( + ele['problem']['index']) + prob = Problem.objects.filter(prob_id=prob_id, platform='F') + if not prob.exists(): + continue + solve, created = Solved.objects.get_or_create(user=user, + problem=prob[0]) + if not created and limit != None: + limit -= 1 + if limit <= 0: + break + continue + return (True, + "Submission data for the given user has been saved successfully.") + + +def UpdateforUserCodechef(user, limit): + if user is None: + return (False, "Given User object cannot be None") + codechef_handle = Profile.objects.get(owner=user).codechef + if codechef_handle is None: + return (False, "codechef_handle cannot be None.") + url = 'https://www.codechef.com/users/' + str(codechef_handle) + res = requests.get(url) + soup = bs4.BeautifulSoup(res.content, 'html.parser') + problems_solved = soup.find( + 'section', {'class': 'rating-data-section problems-solved'}) + if problems_solved is None: + return ( + True, + "Submission data for the given user has been saved successfully.") + if problems_solved.find('h5').text == 'Fully Solved (0)': + return ( + True, + "Submission data for the given user has been saved successfully.") + for ele in problems_solved.find('article').find_all('a'): + prob = Problem.objects.filter(prob_id=ele.text, platform='C') + if not prob.exists(): + continue + solve, created = Solved.objects.get_or_create(problem=prob[0], + user=user) + if not created and limit != None: + limit -= 1 + if limit <= 0: + break + continue + return (True, + "Submission data for the given user has been saved successfully.") + + +def UpdateforUserAtcoder(user, limit): + if user is None: + return (False, "Given User object cannot be None") + atcoder_handle = Profile.objects.get(owner=user).atcoder + if atcoder_handle is None: + return (False, "atcoder_handle cannot be None.") + url = 'https://kenkoooo.com/atcoder/atcoder-api/results?user=' + atcoder_handle + req = requests.get(url) + if req.status_code != 200: + return (False, "User with the given handle does not exist.") + req = req.json() + sorted_req = sorted(req, key=lambda k: k['epoch_second'], reverse=True) + for ele in sorted_req: + if ele['result'] != "AC": + continue + prob = Problem.objects.filter(prob_id=ele['problem_id'], platform='A') + if not prob.exists(): + continue + solve, created = Solved.objects.get_or_create(user=user, + problem=prob[0]) + if not created and limit != None: + limit -= 1 + if limit <= 0: + break + continue + return (True, + "Submission data for the given user has been saved successfully.") + + +def UpdateforUserSpoj(user, limit): + if user is None: + return (False, "Given User object cannot be None") + spoj_handle = Profile.objects.get(owner=user).spoj + if spoj_handle == None: + return (False, "spoj_handle cannot be None.") + url = 'https://www.spoj.com/users/' + spoj_handle + res = requests.get(url) + soup = bs4.BeautifulSoup(res.content, 'html.parser') + problems = soup.find('table', {'class': 'table table-condensed'}) + if problems is None: + return ( + True, + "Submission data for the given user has been saved successfully.") + for ele in problems.find_all('td'): + if ele.text == "": + continue + prob = Problem.objects.filter(prob_id=ele.text, platform='S') + if not prob.exists(): + continue + solve, created = Solved.objects.get_or_create(problem=prob[0], + user=user) + if not created and limit != None: + limit -= 1 + if limit <= 0: + break + continue + return (True, + "Submission data for the given user has been saved successfully.") + + +def UpdateforUserUva(user, limit): + if user is None: + return (False, "Given User object cannot be None") + uva_id = Profile.objects.get(owner=user).uva_id + if uva_id is None: + return (False, "uva_id cannot be None.") + url1 = "https://uhunt.onlinejudge.org/api/subs-user/" + str(uva_id) + req1 = requests.get(url1) + if req1.status_code != 200: + return (False, "User with the given UVA-ID does not exist") + req1 = req1.json() + sorted_req1 = sorted(req1['subs'], key=lambda k: k[4], reverse=True) + for ele in sorted_req1: + if str(ele[2]) != '90': + continue + prob = Problem.objects.filter(prob_id=str(ele[1]), platform='U') + if not prob.exists(): + continue + solve, created = Solved.objects.get_or_create(user=user, + problem=prob[0]) + if not created and limit != None: + limit -= 1 + if limit <= 0: + break + continue + return (True, + "Submission data for the given user has been saved successfully.") diff --git a/codedigger/lists/urls.py b/codedigger/lists/urls.py index d2e986a..176ec70 100644 --- a/codedigger/lists/urls.py +++ b/codedigger/lists/urls.py @@ -20,6 +20,7 @@ SearchUserlistView, ListGetView, EnrollListView, + UpdateForUserView, testing) urlpatterns = [ @@ -65,6 +66,9 @@ path('enroll-list/', EnrollListView.as_view(), name='enroll-list'), path('userlists', SearchUserlistView.as_view(), name='userlist-search'), path('user/', ListGetView.as_view(), name='user-list'), + path('update//', + UpdateForUserView.as_view(), + name='update-codeforces'), # path('/stats', ListStats.as_view(), name='list-stats'), path('/stats/standing', UserStandingStats.as_view(), diff --git a/codedigger/lists/views.py b/codedigger/lists/views.py index 22b2ae9..1d4c4a6 100644 --- a/codedigger/lists/views.py +++ b/codedigger/lists/views.py @@ -7,7 +7,12 @@ GetUserlistSerializer, EditUserlistSerializer, CreateUserlistSerializer, ProblemSerializer, UserlistAddSerializer, AddProblemsAdminSerializer, - EnrollInListSerializer) + EnrollInListSerializer, + UpdateCodeforcesForUserSerializer) +from codeforces.api import user_status +from .solved_update import (UpdateforUserCodeforces, UpdateforUserAtcoder, + UpdateforUserCodechef, UpdateforUserSpoj, + UpdateforUserUva, EnrollInListSerializer) from django.db.models import Q, Subquery, Count from user.permissions import * from user.exception import * @@ -818,6 +823,44 @@ def post(self, request, *args, **kwargs): status=status.HTTP_201_CREATED) +class UpdatesForUserView(generics.GenericAPIView): + permission_classes = [AuthenticatedActivated] + serializer_class = UpdateCodeforcesForUserSerializer + + def post(self, request, *args, **kwargs): + curr_user = self.request.user + data = request.data + platform = self.kwargs['platform'] + username = data.get("username", None) + limit = data.get("limit", None) + if curr_user and curr_user.is_staff and username: + curr_user = User.objects.get(username=username) + if platform == 'F': + returned_status, returned_response = UpdateforUserCodeforces( + curr_user, limit) + if platform == 'C': + returned_status, returned_response = UpdateforUserCodechef( + curr_user, limit) + if platform == 'A': + returned_status, returned_response = UpdateforUserAtcoder( + curr_user, limit) + if platform == 'S': + returned_status, returned_response = UpdateforUserSpoj( + curr_user, limit) + if platform == 'U': + returned_status, returned_response = UpdateforUserUva( + curr_user, limit) + if returned_status: + return response.Response( + { + 'status': 'OK', + 'result': returned_response + }, + status=status.HTTP_200_OK) + else: + return ValidationException(returned_response) + + def testing(request): updater() return JsonResponse({'status': 'OK'})