diff --git a/members/static/js/angular-recaptcha.js b/members/static/js/angular-recaptcha.js deleted file mode 100644 index 5b025ce..0000000 --- a/members/static/js/angular-recaptcha.js +++ /dev/null @@ -1,306 +0,0 @@ -/** - * angular-recaptcha build:2016-04-05 - * https://github.com/vividcortex/angular-recaptcha - * Copyright (c) 2016 VividCortex -**/ - -/*global angular, Recaptcha */ -(function (ng) { - 'use strict'; - - ng.module('vcRecaptcha', []); - -}(angular)); - -/*global angular */ -(function (ng) { - 'use strict'; - - function throwNoKeyException() { - throw new Error('You need to set the "key" attribute to your public reCaptcha key. If you don\'t have a key, please get one from https://www.google.com/recaptcha/admin/create'); - } - - var app = ng.module('vcRecaptcha'); - - /** - * An angular service to wrap the reCaptcha API - */ - app.provider('vcRecaptchaService', function(){ - var provider = this; - var config = {}; - provider.onLoadFunctionName = 'vcRecaptchaApiLoaded'; - - /** - * Sets the reCaptcha configuration values which will be used by default is not specified in a specific directive instance. - * - * @since 2.5.0 - * @param defaults object which overrides the current defaults object. - */ - provider.setDefaults = function(defaults){ - angular.copy(config, defaults); - }; - - /** - * Sets the reCaptcha key which will be used by default is not specified in a specific directive instance. - * - * @since 2.5.0 - * @param siteKey the reCaptcha public key (refer to the README file if you don't know what this is). - */ - provider.setSiteKey = function(siteKey){ - config.key = siteKey; - }; - - /** - * Sets the reCaptcha theme which will be used by default is not specified in a specific directive instance. - * - * @since 2.5.0 - * @param theme The reCaptcha theme. - */ - provider.setTheme = function(theme){ - config.theme = theme; - }; - - /** - * Sets the reCaptcha stoken which will be used by default is not specified in a specific directive instance. - * - * @since 2.5.0 - * @param stoken The reCaptcha stoken. - */ - provider.setStoken = function(stoken){ - config.stoken = stoken; - }; - - /** - * Sets the reCaptcha size which will be used by default is not specified in a specific directive instance. - * - * @since 2.5.0 - * @param size The reCaptcha size. - */ - provider.setSize = function(size){ - config.size = size; - }; - - /** - * Sets the reCaptcha type which will be used by default is not specified in a specific directive instance. - * - * @since 2.5.0 - * @param type The reCaptcha type. - */ - provider.setType = function(type){ - config.type = type; - }; - - /** - * Sets the reCaptcha configuration values which will be used by default is not specified in a specific directive instance. - * - * @since 2.5.0 - * @param onLoadFunctionName string name which overrides the name of the onload function. Should match what is in the recaptcha script querystring onload value. - */ - provider.setOnLoadFunctionName = function(onLoadFunctionName){ - provider.onLoadFunctionName = onLoadFunctionName; - }; - - provider.$get = ['$rootScope','$window', '$q', function ($rootScope, $window, $q) { - var deferred = $q.defer(), promise = deferred.promise, recaptcha; - - $window.vcRecaptchaApiLoadedCallback = $window.vcRecaptchaApiLoadedCallback || []; - - var callback = function () { - recaptcha = $window.grecaptcha; - - deferred.resolve(recaptcha); - }; - - $window.vcRecaptchaApiLoadedCallback.push(callback); - - $window[provider.onLoadFunctionName] = function () { - $window.vcRecaptchaApiLoadedCallback.forEach(function(callback) { - callback(); - }); - }; - - - function getRecaptcha() { - if (!!recaptcha) { - return $q.when(recaptcha); - } - - return promise; - } - - function validateRecaptchaInstance() { - if (!recaptcha) { - throw new Error('reCaptcha has not been loaded yet.'); - } - } - - - // Check if grecaptcha is not defined already. - if (ng.isDefined($window.grecaptcha)) { - callback(); - } - - return { - - /** - * Creates a new reCaptcha object - * - * @param elm the DOM element where to put the captcha - * @param conf the captcha object configuration - * @throws NoKeyException if no key is provided in the provider config or the directive instance (via attribute) - */ - create: function (elm, conf) { - - conf.sitekey = conf.key || config.key; - conf.theme = conf.theme || config.theme; - conf.stoken = conf.stoken || config.stoken; - conf.size = conf.size || config.size; - conf.type = conf.type || config.type; - - if (!conf.sitekey || conf.sitekey.length !== 40) { - throwNoKeyException(); - } - return getRecaptcha().then(function (recaptcha) { - return recaptcha.render(elm, conf); - }); - }, - - /** - * Reloads the reCaptcha - */ - reload: function (widgetId) { - validateRecaptchaInstance(); - - // $log.info('Reloading captcha'); - recaptcha.reset(widgetId); - - // Let everyone know this widget has been reset. - $rootScope.$broadcast('reCaptchaReset', widgetId); - }, - - /** - * Gets the response from the reCaptcha widget. - * - * @see https://developers.google.com/recaptcha/docs/display#js_api - * - * @returns {String} - */ - getResponse: function (widgetId) { - validateRecaptchaInstance(); - - return recaptcha.getResponse(widgetId); - } - }; - - }]; - }); - -}(angular)); - -/*global angular, Recaptcha */ -(function (ng) { - 'use strict'; - - var app = ng.module('vcRecaptcha'); - - app.directive('vcRecaptcha', ['$document', '$timeout', 'vcRecaptchaService', function ($document, $timeout, vcRecaptcha) { - - return { - restrict: 'A', - require: "?^^form", - scope: { - response: '=?ngModel', - key: '=?', - stoken: '=?', - theme: '=?', - size: '=?', - type: '=?', - tabindex: '=?', - required: '=?', - onCreate: '&', - onSuccess: '&', - onExpire: '&' - }, - link: function (scope, elm, attrs, ctrl) { - scope.widgetId = null; - - if(ctrl && angular.isDefined(attrs.required)){ - scope.$watch('required', validate); - } - - var removeCreationListener = scope.$watch('key', function (key) { - var callback = function (gRecaptchaResponse) { - // Safe $apply - $timeout(function () { - scope.response = gRecaptchaResponse; - validate(); - - // Notify about the response availability - scope.onSuccess({response: gRecaptchaResponse, widgetId: scope.widgetId}); - }); - }; - - vcRecaptcha.create(elm[0], { - - callback: callback, - key: key, - stoken: scope.stoken || attrs.stoken || null, - theme: scope.theme || attrs.theme || null, - type: scope.type || attrs.type || null, - tabindex: scope.tabindex || attrs.tabindex || null, - size: scope.size || attrs.size || null, - 'expired-callback': expired - - }).then(function (widgetId) { - // The widget has been created - validate(); - scope.widgetId = widgetId; - scope.onCreate({widgetId: widgetId}); - - scope.$on('$destroy', destroy); - - scope.$on('reCaptchaReset', function(resetWidgetId){ - if(angular.isUndefined(resetWidgetId) || widgetId === resetWidgetId){ - scope.response = ""; - validate(); - } - }) - - }); - - // Remove this listener to avoid creating the widget more than once. - removeCreationListener(); - }); - - function destroy() { - if (ctrl) { - // reset the validity of the form if we were removed - ctrl.$setValidity('recaptcha', null); - } - - cleanup(); - } - - function expired(){ - scope.response = ""; - validate(); - - // Notify about the response availability - scope.onExpire({widgetId: scope.widgetId}); - } - - function validate(){ - if(ctrl){ - ctrl.$setValidity('recaptcha', scope.required === false ? null : Boolean(scope.response)); - } - } - - function cleanup(){ - // removes elements reCaptcha added. - angular.element($document[0].querySelectorAll('.pls-container')).parent().remove(); - } - } - }; - }]); - -}(angular)); diff --git a/members/static/tommy.jpg b/members/static/tommy.jpg deleted file mode 100644 index ee1cb4d..0000000 Binary files a/members/static/tommy.jpg and /dev/null differ diff --git a/members/templates/tommy_blooper.html b/members/templates/tommy_blooper.html deleted file mode 100644 index ef0528b..0000000 --- a/members/templates/tommy_blooper.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "members_base.html" %} - -{% block content %} -

Tommyn jäsenlista

-
- -
-{% endblock content %} diff --git a/members/views.py b/members/views.py index c4b51c3..9f59b75 100644 --- a/members/views.py +++ b/members/views.py @@ -10,52 +10,17 @@ import json import requests import logging - from members.models import Member, Request from members.forms import MemberForm -'''Rest API''' -from members.serializers import MemberSerializer, MemberRequestSerializer -from rest_framework import generics -from rest_framework import generics, status, authentication, exceptions, permissions -from rest_framework.decorators import api_view, permission_classes -from rest_framework.permissions import IsAuthenticated -from members.permissions import HasRights -from members.throttles import BurstRateThrottle, SustainedRateThrottle - # Logger function, you can use the same idea when implementing other loggers to other apps memberlogger = logging.getLogger(__name__) logging.basicConfig(format='[%(levelname)s]%(asctime)s %(message)s', level=settings.LOGGERLEVEL, filename=settings.LOGPATH) -#API views -######################################## -class MembersList(generics.ListCreateAPIView): - queryset = Member.objects.all() - serializer_class = MemberSerializer - permission_classes = (HasRights, permissions.IsAuthenticated, ) - throttle_classes = (BurstRateThrottle, SustainedRateThrottle, ) - -class MemberDetails(generics.RetrieveUpdateDestroyAPIView): - queryset = Member.objects.all() - serializer_class = MemberSerializer - permission_classes = (HasRights, permissions.IsAuthenticated, ) - throttle_classes = (BurstRateThrottle, SustainedRateThrottle, ) - -class MemberRequestList(generics.ListCreateAPIView): - queryset = Request.objects.all() - serializer_class = MemberRequestSerializer - permission_classes = (HasRights, permissions.IsAuthenticated, ) - throttle_classes = (BurstRateThrottle, SustainedRateThrottle, ) - -class MemberRequestDetail(generics.RetrieveUpdateDestroyAPIView): - queryset = Request.objects.all() - serializer_class = MemberRequestSerializer - permission_classes = (HasRights, permissions.IsAuthenticated, ) - throttle_classes = (BurstRateThrottle, SustainedRateThrottle, ) - -######################################## -# function to validate reCaptcha +''' +Recaptcha is used in member applications +''' def validate_recaptcha(response): values = { 'secret': settings.GOOGLE_RECAPTCHA_SECRET_KEY, @@ -173,11 +138,6 @@ def delete_member(request, *args, **kwargs): def list_applications(request, *args, **kwargs): return render(request, 'list_applications.html', {}) -@ensure_csrf_cookie -@require_http_methods(["GET"]) -@permission_required('members.change_member', login_url='/login') -def tommy_blooper(request, *args, **kwargs): - return render(request, 'tommy_blooper.html', {}) @ensure_csrf_cookie @require_http_methods(["GET"]) @@ -201,51 +161,17 @@ def edit_application(request, *args, **kwargs): else: return render(request, 'edit_application.html', {'member_id' : i}) + @ensure_csrf_cookie def application_index(request, *args, **kwargs): return render(request, 'application_index.html', {}) + @ensure_csrf_cookie def application_success_index(request, *args, **kwargs): return render(request, 'application_success.html', {}) -@ensure_csrf_cookie -@require_http_methods(["GET"]) -@permission_required('members.change_member', login_url='/login') -def members(request, *args, **kwargs): - mems = list(map(lambda m: m.get_dict(), Member.objects.all())) - return HttpResponse(json.dumps(mems)) - - -@ensure_csrf_cookie -@require_http_methods(["GET", "POST", "DELETE", "PUT"]) -@permission_required('members.change_member', login_url='/login') -def member(request, *args, **kwargs): - - # get, put and delete together since all operate on existing objects - if request.method in ['GET', 'PUT', 'DELETE']: - - # get object by id or give 404 - idx = kwargs.pop("idx", None) - try: - mem = Member.objects.get(pk=idx) - except Member.DoesNotExist: - resp = HttpResponse('{"error":"object not found"}') - resp.status_code = 404 - return resp - - # delete object if requested - if request.method == 'DELETE': - try: - mem.delete() - return HttpResponse('{"status":"success"}') - except: - resp = HttpResponse('{"error" : "could not delete object"}') - resp.status_code = 500 - return resp - - @ensure_csrf_cookie @require_http_methods(["POST"]) @permission_required('members.change_member', login_url='/login') @@ -266,72 +192,6 @@ def csv_import(request, *args, **kwargs): return resp -@ensure_csrf_cookie -@require_http_methods(["GET"]) -@permission_required('members.change_member', login_url='/login') -def member_requests(request, *args, **kwargs): - reqs = list(map(lambda r: r.get_dict(), MemberRequest.objects.all())) - return HttpResponse(json.dumps(reqs)) - - -@ensure_csrf_cookie -def new_member_request(request, *args, **kwargs): - try: - data = json.loads(request.body.decode("utf-8")) - # get captcha response from member - captcha = data.pop("reCaptchaResponse", "") - # send response to google and check it out - captcha_ok = validate_recaptcha(captcha) - # if not ok, inform user - if not captcha_ok: - return HttpResponseBadRequest('{"error": "Captcha not ok. Please try again."}') - # if ok continue - mem = Member.create_from_dict(data) - req = MemberRequest.objects.create(member=mem) - - # Build the email body - subject = 'New application' - message = 'You have new application\r\n' - message += 'Member info:\r\n' - message += 'First name: ' + mem.first_name + '\r\n' - message += 'Last name: ' + mem.last_name + '\r\n' - message += 'Email: ' + mem.email + '\r\n' - message += 'Place of residence: ' + mem.POR + '\r\n' - message += 'AYY-membership: ' + str(mem.AYY) + '\r\n' - message += 'To mail list: ' + str(mem.jas) + '\r\n' - message += 'Created: ' + mem.created.isoformat(' ') + '\r\n' - message += 'Please go to the https://sika.sahkoinsinoorikilta.fi/members/ and do something about it!\r\n' - - # TODO: send mail when application is ready - # send_mail_wrapper(subject, message) - - return HttpResponse(json.dumps(mem.get_dict())) - - except ValueError: - return HttpResponseBadRequest('{"error" : "Invalid parameters supplied"}') - except TimeoutError: - return HttpResponseBadRequest('{"error" : "Much error, no connection"}') - - -@ensure_csrf_cookie -@require_http_methods(["GET", "POST", "DELETE"]) -@permission_required('members.change_member', login_url='/login') -def handle_mem_request(request, idx, *args, **kwargs): - try: - req = MemberRequest.objects.get(pk=idx) - except MemberRequest.DoesNotExist: - resp = HttpResponse('{"error":"object not found"}') - resp.status_code = 404 - return resp - if request.method == 'GET': - return HttpResponse(json.dumps(req.get_dict())) - elif request.method == 'DELETE': - req.member.delete() - else: # method == POST because other aren't allowed here - req.delete() - return HttpResponse('{"status":"success"}') - - @ensure_csrf_cookie @require_http_methods(["GET"]) @permission_required('members.change_member', login_url='/login')