From 1b4f5e4e88d870a67e6ec36e17697349c18410e1 Mon Sep 17 00:00:00 2001 From: Adarnof Date: Sun, 16 Oct 2016 18:01:14 -0400 Subject: [PATCH] Adarnof's Little Things (#547) * Port to Django 1.10 Initial migrations for current states of all models. Requires faking to retain data. Removed all references to render_to_response, replacing with render shortcut. Same for HttpResponseRedirect to render shortcut. Corrected notification signal import to wait for app registry to finish loading. * Correct typos from render conversion * Modify models to suppress Django field warnings * Script for automatic database conversion - fakes initial migrations to preserve data Include LOGIN_URL setting * Correct context processor import typo * Removed pathfinder support. Current pathfinder versions require SSO, not APIs added to database. Conditionally load additional database definitions only if services are enabled. Prevents errors when running auth without creating all possible databases. * Condense context processors * Include Django 1.10 installation in migrate script Remove syncdb/evolve, replace with migrate for update script * Replaced member/blue perms with user state system Removed sigtracker Initial migrations for default perms and groups Removed perm bootstrapping on first run * Clean up services list * Remove fleet fittings page * Provide action feedback via django messaging Display unread notification count Correct left navbar alignment * Stop storing service passwords. Provide them one time upon activation or reset. Closes #177 * Add group sync buttons to admin site Allow searcing of AuthServicesInfo models Display user main character * Correct button CSS to remove underlines on hover * Added bulk actions to notifications Altered notification default ordering * Centralize API key validation. Remove unused error count on API key model. Restructure API key refresh task to queue all keys per user and await completion. Closes #350 * Example configuration files for supervisor. Copy to /etc/supervisor/conf.d and restart to take effect. Closes #521 Closes #266 * Pre-save receiver for member/blue state switching Removed is_blue field Added link to admin site * Remove all hardcoded URLs from views and templates Correct missing render arguments Closes #540 * Correct celeryd process directory * Migration to automatically set user states. Runs instead of waiting for next API refresh cycle. Should make the transition much easier. * Verify service accounts accessible to member state * Restructure project to remove unnecessary apps. (celerytask, util, portal, registraion apps) Added workarounds for python 3 compatibility. * Correct python2 compatibility * Check services against state being changed to * Python3 compatibility fixes * Relocate x2bool py3 fix * SSO integration for logging in to existing accounts. * Add missing url names for fleetup reverse * Sanitize groupnames before syncing. * Correct trailing slash preventing url resolution * Alter group name sanitization to allow periods and hyphens * Correct state check on pre_save model for corp/alliance group assignment * Remove sigtracker table from old dbs to allow user deletion * Include missing celery configuration * Teamspeak error handling * Prevent celery worker deadlock on async group result wait * Correct active navbar links for translated urls. Correct corp status url resolution for some links. Remove DiscordAuthToken model. --- .gitignore | 7 + .idea/allianceauth.iml | 5 +- .idea/dataSources.xml | 14 +- .idea/misc.xml | 8 +- README.md | 7 +- alliance_auth/__init__.py | 1 + alliance_auth/settings.py.example | 273 +++-- alliance_auth/urls.py | 534 ++++----- alliance_auth/wsgi.py | 9 +- authentication/__init__.py | 2 + authentication/admin.py | 145 ++- authentication/apps.py | 10 + authentication/context_processors.py | 25 + authentication/decorators.py | 33 + authentication/forms.py | 37 +- authentication/managers.py | 112 +- authentication/migrations/0001_initial.py | 52 + .../migrations/0002_auto_20160907_1914.py | 23 + .../migrations/0003_authservicesinfo_state.py | 20 + .../migrations/0004_create_permissions.py | 43 + .../migrations/0005_delete_perms.py | 31 + .../migrations/0006_auto_20160910_0542.py | 51 + .../0007_remove_authservicesinfo_is_blue.py | 19 + authentication/migrations/0008_set_state.py | 66 ++ .../migrations}/__init__.py | 0 authentication/models.py | 23 +- authentication/signals.py | 25 + authentication/states.py | 4 + authentication/tasks.py | 168 +++ authentication/views.py | 99 +- celerytask/__init__.py | 1 - celerytask/admin.py | 7 - celerytask/models.py | 12 - celerytask/tasks.py | 785 ------------- celerytask/tests.py | 1 - celerytask/views.py | 1 - corputils/__init__.py | 1 + corputils/admin.py | 1 + corputils/apps.py | 7 + corputils/forms.py | 7 +- corputils/models.py | 1 + corputils/views.py | 97 +- eveonline/__init__.py | 1 + eveonline/admin.py | 19 +- eveonline/apps.py | 7 + eveonline/forms.py | 66 +- eveonline/managers.py | 27 +- eveonline/migrations/0001_initial.py | 68 ++ .../0002_remove_eveapikeypair_error_count.py | 19 + .../migrations}/__init__.py | 0 eveonline/models.py | 7 +- eveonline/tasks.py | 346 ++++++ eveonline/views.py | 96 +- fleetactivitytracking/__init__.py | 1 + fleetactivitytracking/admin.py | 3 +- fleetactivitytracking/apps.py | 7 + fleetactivitytracking/forms.py | 7 +- .../migrations/0001_initial.py | 59 + .../migrations/0002_auto_20160905_2220.py | 22 + .../migrations/0003_auto_20160906_2354.py | 21 + .../migrations}/__init__.py | 0 fleetactivitytracking/models.py | 11 +- fleetactivitytracking/views.py | 112 +- fleetup/__init__.py | 1 + fleetup/admin.py | 1 + fleetup/apps.py | 7 + fleetup/forms.py | 1 + fleetup/models.py | 1 + fleetup/views.py | 53 +- groupmanagement/__init__.py | 1 + groupmanagement/admin.py | 9 +- groupmanagement/apps.py | 7 + groupmanagement/migrations/0001_initial.py | 54 + .../migrations/0002_auto_20160906_2354.py | 26 + .../migrations/0003_default_groups.py | 24 + groupmanagement/migrations/__init__.py | 0 groupmanagement/models.py | 12 +- groupmanagement/views.py | 123 +- hrapplications/__init__.py | 1 + hrapplications/admin.py | 11 +- hrapplications/apps.py | 7 + hrapplications/forms.py | 3 + hrapplications/migrations/0001_initial.py | 127 +++ hrapplications/migrations/__init__.py | 0 hrapplications/models.py | 21 +- hrapplications/views.py | 90 +- manage.py | 19 +- notifications/__init__.py | 4 +- notifications/admin.py | 1 + notifications/apps.py | 7 + notifications/context_processors.py | 6 +- notifications/handlers.py | 8 +- notifications/migrations/0001_initial.py | 31 + .../migrations/0002_auto_20160910_1649.py | 19 + notifications/migrations/__init__.py | 0 notifications/models.py | 13 +- notifications/tests.py | 2 - notifications/views.py | 30 +- optimer/__init__.py | 1 + optimer/admin.py | 4 +- optimer/apps.py | 7 + optimer/form.py | 4 +- optimer/migrations/0001_initial.py | 39 + optimer/migrations/__init__.py | 0 optimer/models.py | 7 +- optimer/views.py | 60 +- portal/admin.py | 1 - portal/models.py | 1 - portal/tests.py | 1 - portal/views.py | 30 - registration/admin.py | 1 - registration/forms.py | 44 - registration/models.py | 1 - registration/tests.py | 1 - registration/views.py | 40 - requirements.txt | 18 +- run_alliance_corp_update.py | 5 +- services/__init__.py | 2 + services/admin.py | 12 +- services/apps.py | 10 + services/context_processors.py | 31 + services/forms.py | 12 +- services/managers/__init__.py | 1 + services/managers/discord_manager.py | 470 +------- services/managers/discourse_manager.py | 32 +- services/managers/eve_api_manager.py | 132 ++- services/managers/evewho_manager.py | 14 +- services/managers/fleetup_manager.py | 131 ++- services/managers/ipboard_manager.py | 36 +- services/managers/ips4_manager.py | 14 +- services/managers/market_manager.py | 21 +- services/managers/mumble_manager.py | 24 +- services/managers/openfire_manager.py | 96 +- services/managers/pathfinder_manager.py | 196 ---- services/managers/phpbb3_manager.py | 30 +- services/managers/smf_manager.py | 42 +- services/managers/srp_manager.py | 59 +- services/managers/teamspeak3_manager.py | 68 +- services/managers/util/__init__.py | 1 + services/managers/util/ts3.py | 235 +++- services/managers/xenforo_manager.py | 222 ++-- services/migrations/0001_initial.py | 83 ++ .../migrations/0002_auto_20161016_0135.py | 22 + services/migrations/__init__.py | 0 services/models.py | 27 +- {celerytask => services}/signals.py | 34 +- services/tasks.py | 403 ++++++- services/views.py | 1002 +++++++++-------- sigtracker/admin.py | 6 - sigtracker/form.py | 26 - sigtracker/models.py | 22 - sigtracker/tests.py | 1 - sigtracker/views.py | 122 -- srp/__init__.py | 1 + srp/admin.py | 8 +- srp/apps.py | 7 + srp/form.py | 2 +- srp/migrations/0001_initial.py | 48 + srp/migrations/__init__.py | 0 srp/models.py | 6 +- srp/views.py | 209 ++-- .../sso/EVE_SSO_Login_Buttons_Large_Black.png | Bin 0 -> 2308 bytes .../sso/EVE_SSO_Login_Buttons_Large_White.png | Bin 0 -> 2248 bytes stock/templates/public/base.html | 172 +-- stock/templates/public/login.html | 37 +- stock/templates/registered/addsignature.html | 39 - .../templates/registered/apikeymanagment.html | 14 +- stock/templates/registered/characters.html | 15 +- stock/templates/registered/corputils.html | 8 +- .../registered/corputilssearchview.html | 6 +- stock/templates/registered/dashboard.html | 7 +- stock/templates/registered/discord.html | 35 - .../fatlinkpersonalmonthlystatisticsview.html | 8 +- .../fatlinkpersonalstatisticsview.html | 8 +- .../registered/fatlinkstatisticsview.html | 8 +- stock/templates/registered/fatlinkview.html | 17 +- stock/templates/registered/fleetfits.html | 20 - .../registered/fleetfits.html.example | 19 - stock/templates/registered/fleetup.html | 8 +- .../registered/fleetupcharacters.html | 10 +- .../templates/registered/fleetupdoctrine.html | 10 +- .../registered/fleetupdoctrinesview.html | 12 +- .../templates/registered/fleetupfitting.html | 12 +- .../registered/fleetupfittingsview.html | 12 +- .../templates/registered/groupmanagement.html | 24 +- stock/templates/registered/groups.html | 14 +- .../registered/hrapplicationmanagement.html | 22 +- .../registered/hrapplicationsearchview.html | 5 +- .../registered/hrapplicationview.html | 8 +- .../registered/hrcreateapplication.html | 33 - .../registered/notification_list.html | 32 +- .../registered/operationmanagement.html | 42 +- .../registered/service_credentials.html | 23 + .../registered/service_password.html | 9 - stock/templates/registered/services.html | 631 ++--------- .../registered/signaturemanagement.html | 78 -- .../templates/registered/signatureupdate.html | 46 - stock/templates/registered/srpfleetadd.html | 7 +- stock/templates/registered/srpfleetdata.html | 48 +- .../registered/srpfleetrequestamount.html | 18 +- stock/templates/registered/srpmanagement.html | 35 +- .../templates/registered/timermanagement.html | 47 +- .../registration/password_reset_complete.html | 4 +- ten_migrate.sh | 23 + thirdparty/Mumble/authenticator.py | 424 +++---- thirdparty/Supervisor/auth-celerybeat.conf | 10 + thirdparty/Supervisor/auth-celeryd.conf | 13 + thirdparty/Supervisor/auth-mumble.conf | 13 + timerboard/__init__.py | 1 + timerboard/admin.py | 4 +- timerboard/apps.py | 7 + timerboard/form.py | 11 +- timerboard/migrations/0001_initial.py | 40 + timerboard/migrations/__init__.py | 0 timerboard/models.py | 7 + timerboard/views.py | 78 +- update.sh | 3 +- util/__init__.py | 77 -- util/common_task.py | 94 -- util/context_processors.py | 68 -- 220 files changed, 5716 insertions(+), 5331 deletions(-) create mode 100644 authentication/apps.py create mode 100644 authentication/context_processors.py create mode 100644 authentication/decorators.py create mode 100644 authentication/migrations/0001_initial.py create mode 100644 authentication/migrations/0002_auto_20160907_1914.py create mode 100644 authentication/migrations/0003_authservicesinfo_state.py create mode 100644 authentication/migrations/0004_create_permissions.py create mode 100644 authentication/migrations/0005_delete_perms.py create mode 100644 authentication/migrations/0006_auto_20160910_0542.py create mode 100644 authentication/migrations/0007_remove_authservicesinfo_is_blue.py create mode 100644 authentication/migrations/0008_set_state.py rename {portal => authentication/migrations}/__init__.py (100%) create mode 100644 authentication/signals.py create mode 100644 authentication/states.py create mode 100644 authentication/tasks.py delete mode 100644 celerytask/__init__.py delete mode 100644 celerytask/admin.py delete mode 100755 celerytask/models.py delete mode 100644 celerytask/tasks.py delete mode 100644 celerytask/tests.py delete mode 100644 celerytask/views.py create mode 100644 corputils/apps.py create mode 100644 eveonline/apps.py create mode 100644 eveonline/migrations/0001_initial.py create mode 100644 eveonline/migrations/0002_remove_eveapikeypair_error_count.py rename {registration => eveonline/migrations}/__init__.py (100%) create mode 100644 eveonline/tasks.py create mode 100644 fleetactivitytracking/apps.py create mode 100644 fleetactivitytracking/migrations/0001_initial.py create mode 100644 fleetactivitytracking/migrations/0002_auto_20160905_2220.py create mode 100644 fleetactivitytracking/migrations/0003_auto_20160906_2354.py rename {sigtracker => fleetactivitytracking/migrations}/__init__.py (100%) create mode 100644 fleetup/apps.py create mode 100644 groupmanagement/apps.py create mode 100644 groupmanagement/migrations/0001_initial.py create mode 100644 groupmanagement/migrations/0002_auto_20160906_2354.py create mode 100644 groupmanagement/migrations/0003_default_groups.py create mode 100644 groupmanagement/migrations/__init__.py create mode 100644 hrapplications/apps.py create mode 100644 hrapplications/migrations/0001_initial.py create mode 100644 hrapplications/migrations/__init__.py create mode 100644 notifications/apps.py create mode 100644 notifications/migrations/0001_initial.py create mode 100644 notifications/migrations/0002_auto_20160910_1649.py create mode 100644 notifications/migrations/__init__.py create mode 100644 optimer/apps.py create mode 100644 optimer/migrations/0001_initial.py create mode 100644 optimer/migrations/__init__.py delete mode 100644 portal/admin.py delete mode 100644 portal/models.py delete mode 100644 portal/tests.py delete mode 100755 portal/views.py delete mode 100644 registration/admin.py delete mode 100644 registration/forms.py delete mode 100644 registration/models.py delete mode 100644 registration/tests.py delete mode 100644 registration/views.py create mode 100644 services/apps.py create mode 100644 services/context_processors.py delete mode 100644 services/managers/pathfinder_manager.py create mode 100644 services/migrations/0001_initial.py create mode 100644 services/migrations/0002_auto_20161016_0135.py create mode 100644 services/migrations/__init__.py rename {celerytask => services}/signals.py (81%) delete mode 100644 sigtracker/admin.py delete mode 100644 sigtracker/form.py delete mode 100644 sigtracker/models.py delete mode 100644 sigtracker/tests.py delete mode 100644 sigtracker/views.py create mode 100644 srp/apps.py create mode 100644 srp/migrations/0001_initial.py create mode 100644 srp/migrations/__init__.py create mode 100644 stock/static/img/sso/EVE_SSO_Login_Buttons_Large_Black.png create mode 100644 stock/static/img/sso/EVE_SSO_Login_Buttons_Large_White.png delete mode 100644 stock/templates/registered/addsignature.html delete mode 100644 stock/templates/registered/discord.html delete mode 100644 stock/templates/registered/fleetfits.html delete mode 100644 stock/templates/registered/fleetfits.html.example delete mode 100644 stock/templates/registered/hrcreateapplication.html create mode 100644 stock/templates/registered/service_credentials.html delete mode 100644 stock/templates/registered/signaturemanagement.html delete mode 100644 stock/templates/registered/signatureupdate.html create mode 100755 ten_migrate.sh create mode 100644 thirdparty/Supervisor/auth-celerybeat.conf create mode 100644 thirdparty/Supervisor/auth-celeryd.conf create mode 100644 thirdparty/Supervisor/auth-mumble.conf create mode 100644 timerboard/apps.py create mode 100644 timerboard/migrations/0001_initial.py create mode 100644 timerboard/migrations/__init__.py delete mode 100755 util/__init__.py delete mode 100755 util/common_task.py delete mode 100755 util/context_processors.py diff --git a/.gitignore b/.gitignore index 9f48ec85..cd472cd5 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,10 @@ nginx_config.txt # custom staticfiles static/* + +#celerybeat +*.pid +celerybeat-schedule + +#pycharm +.idea/* \ No newline at end of file diff --git a/.idea/allianceauth.iml b/.idea/allianceauth.iml index a89267e9..a40b16c4 100755 --- a/.idea/allianceauth.iml +++ b/.idea/allianceauth.iml @@ -4,15 +4,16 @@ - + diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml index b7866743..fe8e8466 100644 --- a/.idea/dataSources.xml +++ b/.idea/dataSources.xml @@ -1,30 +1,20 @@ - + mysql com.mysql.jdbc.Driver jdbc:mysql://127.0.0.1:3306/alliance_auth - allianceauth - dfcbdfc6dfc6dfc3dfcbdfc4dfc9dfcfdfcbdfdfdfdedfc2 - mysql com.mysql.jdbc.Driver jdbc:mysql://127.0.0.1:3306/alliance_forum - allianceauth - dfcbdfc6dfc6dfc3dfcbdfc4dfc9dfcfdfcbdfdfdfdedfc2 - mysql com.mysql.jdbc.Driver jdbc:mysql://127.0.0.1:3306/alliance_mumble - alliancemumble - dfcbdfc6dfc6dfc3dfcbdfc4dfc9dfcfdfc7dfdfdfc7dfc8dfc6dfcf - - - + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 9e616ddf..c33bd879 100755 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,5 +1,7 @@ - - - + + + + \ No newline at end of file diff --git a/README.md b/README.md index b600ad1a..ebb6c921 100755 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Join us in-game in the channel allianceauth for help and feature requests. Special Thanks: - Thanking Nikdoof, without his old auth implementation this project wouldn't be as far as it is now. + Thanks to Nikdoof, without his old auth implementation this project wouldn't be as far as it is now. Note: @@ -29,8 +29,7 @@ Note: Requirements: # Django Stuff # - django 1.6.1 - django-evolution + django 1.10.1 django-bootstrap-form django-celery @@ -58,11 +57,9 @@ Vagrant Instructions: Special Permissions In Admin: - auth | user | alliance_member ( Added auto by auth when a member is verified ) auth | user | group_management ( Access to add members to groups within the alliance ) auth | user | jabber_broadcast ( Access to broadcast a message over jabber to own groups) auth | user | jabber_broadcast_all ( Can choose from all groups and the 'all' option when broadcasting) - auth | user | blue_member ( Auto Added to people who register has a blue when adding api key) auth | user | corp_apis ( View APIs, and jackKnife, of all members in user's corp. ) auth | user | alliance_apis ( View APIs, and jackKnife, of all member in user's alliance member corps. ) auth | user | timer_management ( Access to create and remove timers) diff --git a/alliance_auth/__init__.py b/alliance_auth/__init__.py index e69de29b..519ff49e 100644 --- a/alliance_auth/__init__.py +++ b/alliance_auth/__init__.py @@ -0,0 +1 @@ +from __future__ import unicode_literals \ No newline at end of file diff --git a/alliance_auth/settings.py.example b/alliance_auth/settings.py.example index 22d53359..3fc5f6d7 100644 --- a/alliance_auth/settings.py.example +++ b/alliance_auth/settings.py.example @@ -1,43 +1,46 @@ """ -vim: set filetype=python: Django settings for alliance_auth project. +Generated by 'django-admin startproject' using Django 1.10.1. + For more information on this file, see -https://docs.djangoproject.com/en/1.6/topics/settings/ +https://docs.djangoproject.com/en/1.10/topics/settings/ For the full list of settings and their values, see -https://docs.djangoproject.com/en/1.6/ref/settings/ - +https://docs.djangoproject.com/en/1.10/ref/settings/ """ -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) import os import djcelery +from django.contrib import messages + djcelery.setup_loader() -BASE_DIR = os.path.dirname(os.path.dirname(__file__)) + +# Celery configuration +BROKER_URL = 'amqp://guest:guest@localhost:5672/' +CELERYBEAT_SCHEDULER = "djcelery.schedulers.DatabaseScheduler" + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + # Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/ +# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -# Generate a new key here: http://www.miniwebtool.com/django-secret-key-generator/ -SECRET_KEY = os.environ.get('AA_SECRET_KEY', '5xvh4e0x&@-$6(kj%4^80pdo1n5v-!mtx(e(1tw@kn-1le*ts@') +SECRET_KEY = '' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = 'True' == os.environ.get('AA_DEBUG','True') -TEMPLATE_DEBUG = True +ALLOWED_HOSTS = [] -ALLOWED_HOSTS = ['127.0.0.1','yourdomain.com','www.yourdomain.com'] - -BROKER_URL = 'amqp://guest:guest@localhost:5672/' - -CELERYBEAT_SCHEDULER = "djcelery.schedulers.DatabaseScheduler" # Application definition -INSTALLED_APPS = ( + +INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', @@ -45,27 +48,25 @@ INSTALLED_APPS = ( 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.humanize', - 'django_evolution', 'djcelery', - 'celerytask', 'bootstrapform', 'authentication', - 'portal', - 'registration', 'services', 'eveonline', 'groupmanagement', 'hrapplications', 'timerboard', 'srp', - 'sigtracker', 'optimer', 'corputils', 'fleetactivitytracking', 'notifications', -) + 'eve_sso', + 'geelweb.django.navhelper', +] -MIDDLEWARE_CLASSES = ( +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', @@ -73,7 +74,9 @@ MIDDLEWARE_CLASSES = ( 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.locale.LocaleMiddleware', -) +] + +ROOT_URLCONF = 'alliance_auth.urls' LOCALE_PATHS = ( os.path.join(BASE_DIR, 'locale/'), @@ -85,105 +88,75 @@ LANGUAGES = ( ('de', ugettext('German')), ) -ROOT_URLCONF = 'alliance_auth.urls' +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ + os.path.join(BASE_DIR, 'customization/templates'), + os.path.join(BASE_DIR, 'stock/templates'), + ], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + 'django.template.context_processors.i18n', + 'django.template.context_processors.media', + 'django.template.context_processors.static', + 'django.template.context_processors.tz', + 'services.context_processors.auth_settings', + 'notifications.context_processors.user_notification_count', + 'authentication.context_processors.states', + 'authentication.context_processors.membership_state', + 'authentication.context_processors.sso', + ], + }, + }, +] WSGI_APPLICATION = 'alliance_auth.wsgi.application' + # Database -# https://docs.djangoproject.com/en/1.6/ref/settings/#databases +# https://docs.djangoproject.com/en/1.10/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'alliance_auth', + 'NAME': 'aa_test', 'USER': os.environ.get('AA_DB_DEFAULT_USER', 'allianceserver'), 'PASSWORD': os.environ.get('AA_DB_DEFAULT_PASSWORD', 'password'), 'HOST': os.environ.get('AA_DB_DEFAULT_HOST', '127.0.0.1'), 'PORT': os.environ.get('AA_DB_DEFAULT_PORT', '3306'), }, - - 'phpbb3': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'alliance_forum', - 'USER': os.environ.get('AA_DB_PHPBB3_USER', 'allianceserver'), - 'PASSWORD': os.environ.get('AA_DB_PHPBB3_PASSWORD', 'password'), - 'HOST': os.environ.get('AA_DB_PHPBB3_HOST', '127.0.0.1'), - 'PORT': os.environ.get('AA_DB_PHPBB3_PORT', '3306'), - }, - - 'ips4': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'alliance_ips4', - 'USER': os.environ.get('AA_DB_IPS4_USER', 'allianceserver'), - 'PASSWORD': os.environ.get('AA_DB_IPS4_PASSWORD', 'password'), - 'HOST': os.environ.get('AA_DB_IPS4_HOST', '127.0.0.1'), - 'PORT': os.environ.get('AA_DB_IPS4_PORT', '3306'), - }, - - 'smf': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'alliance_smf', - 'USER': os.environ.get('AA_DB_SMF_USER', 'allianceserver'), - 'PASSWORD': os.environ.get('AA_DB_SMF_PASSWORD', 'password'), - 'HOST': os.environ.get('AA_DB_SMF_HOST', '127.0.0.1'), - 'PORT': os.environ.get('AA_DB_SMF_PORT', '3306'), - }, - - 'market': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'alliance_market', - 'USER': os.environ.get('AA_DB_MARKET_USER', 'allianceserver'), - 'PASSWORD': os.environ.get('AA_DB_MARKET_PASSWORD', 'password'), - 'HOST': os.environ.get('AA_DB_MARKET_HOST', '127.0.0.1'), - 'PORT': os.environ.get('AA_DB_MARKET_PORT', '3306'), - }, - - 'pathfinder': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'alliance_pathfinder', - 'USER': os.environ.get('AA_DB_PATHFINDER_USER', 'allianceserver'), - 'PASSWORD': os.environ.get('AA_DB_PATHFINDER_PASSWORD', 'password'), - 'HOST': os.environ.get('AA_DB_PATHFINDER_HOST', '127.0.0.1'), - 'PORT': os.environ.get('AA_DB_PATHFINDER_PORT', '3306'), - } - } -TEMPLATE_CONTEXT_PROCESSORS = ( - 'django.contrib.auth.context_processors.auth', - 'django.core.context_processors.debug', - 'django.core.context_processors.i18n', - 'django.core.context_processors.media', - 'django.core.context_processors.static', - 'django.core.context_processors.tz', - 'django.contrib.messages.context_processors.messages', - 'django.core.context_processors.request', - 'util.context_processors.is_corp', - 'util.context_processors.corp_id', - 'util.context_processors.corp_name', - 'util.context_processors.alliance_id', - 'util.context_processors.alliance_name', - 'util.context_processors.jabber_url', - 'util.context_processors.domain_url', - 'util.context_processors.member_api_mask', - 'util.context_processors.blue_api_mask', - 'notifications.context_processors.user_notification_count', -) +# Password validation +# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators -TEMPLATE_DIRS = ( - os.path.join(BASE_DIR, 'customization/templates'), - os.path.join(BASE_DIR, 'stock/templates'), -) +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] -STATICFILES_DIRS = ( - os.path.join(BASE_DIR, "customization/static"), - os.path.join(BASE_DIR, "stock/static"), -) +LOGIN_URL = 'auth_login_user' -LOGIN_URL = '/login_user/' +SUPERUSER_STATE_BYPASS = 'True' == os.environ.get('AA_SUPERUSER_STATE_BYPASS', 'True') # Internationalization -# https://docs.djangoproject.com/en/1.6/topics/i18n/ +# https://docs.djangoproject.com/en/1.10/topics/i18n/ LANGUAGE_CODE = os.environ.get('AA_LANGUAGE_CODE', 'en-us') @@ -195,11 +168,21 @@ USE_L10N = True USE_TZ = True -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/1.6/howto/static-files/ -STATIC_URL = '/static/' -STATIC_ROOT = '/home/allianceserver/allianceauth/static/' +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.10/howto/static-files/ + +STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(BASE_DIR, "static") +STATICFILES_DIRS = ( + os.path.join(BASE_DIR, "customization/static"), + os.path.join(BASE_DIR, "stock/static"), +) + +# Bootstrap messaging css workaround +MESSAGE_TAGS = { + messages.ERROR: 'danger' +} ##################################################### ## @@ -216,7 +199,6 @@ STATIC_ROOT = '/home/allianceserver/allianceauth/static/' ########################### IS_CORP = 'True' == os.environ.get('AA_IS_CORP', 'True') - ################# # EMAIL SETTINGS ################# @@ -245,7 +227,19 @@ EMAIL_USE_TLS = 'True' == os.environ.get('AA_EMAIL_USE_TLS', 'True') KILLBOARD_URL = os.environ.get('AA_KILLBOARD_URL', '') EXTERNAL_MEDIA_URL = os.environ.get('AA_EXTERNAL_MEDIA_URL', '') FORUM_URL = os.environ.get('AA_FORUM_URL', '') -SMF_URL = os.environ.get('AA_SMF_URL', '') + +################### +# SSO Settings +################### +# Optional SSO. +# Get client ID and client secret from registering an app at +# https://developers.eveonline.com/ +# Callback URL should be http://mydomain.com/sso/callback +# Leave callback blank to hide SSO button on login page +################### +EVE_SSO_CLIENT_ID = os.environ.get('AA_EVE_SSO_CLIENT_ID', '') +EVE_SSO_CLIENT_SECRET = os.environ.get('AA_EVE_SSO_CLIENT_SECRET', '') +EVE_SSO_CALLBACK_URL = os.environ.get('AA_EVE_SSO_CALLBACK_URL', '') ######################### # Default Group Settings @@ -287,7 +281,6 @@ ENABLE_AUTH_DISCOURSE = 'True' == os.environ.get('AA_ENABLE_AUTH_DISCOURSE', 'Fa ENABLE_AUTH_IPS4 = 'True' == os.environ.get('AA_ENABLE_AUTH_IPS4', 'False') ENABLE_AUTH_SMF = 'True' == os.environ.get('AA_ENABLE_AUTH_SMF', 'False') ENABLE_AUTH_MARKET = 'True' == os.environ.get('AA_ENABLE_AUTH_MARKET', 'False') -ENABLE_AUTH_PATHFINDER = 'True' == os.environ.get('AA_ENABLE_AUTH_PATHFINDER', 'False') ENABLE_AUTH_XENFORO = 'True' == os.environ.get('AA_ENABLE_AUTH_XENFORO', 'False') ##################### @@ -317,7 +310,6 @@ ENABLE_BLUE_DISCOURSE = 'True' == os.environ.get('AA_ENABLE_BLUE_DISCOURSE', 'Fa ENABLE_BLUE_IPS4 = 'True' == os.environ.get('AA_ENABLE_BLUE_IPS4', 'False') ENABLE_BLUE_SMF = 'True' == os.environ.get('AA_ENABLE_BLUE_SMF', 'False') ENABLE_BLUE_MARKET = 'True' == os.environ.get('AA_ENABLE_BLUE_MARKET', 'False') -ENABLE_BLUE_PATHFINDER = 'True' == os.environ.get('AA_ENABLE_BLUE_PATHFINDER', 'False') ENABLE_BLUE_XENFORO = 'True' == os.environ.get('AA_ENABLE_BLUE_XENFORO', 'False') ######################### @@ -360,15 +352,18 @@ BLUE_API_ACCOUNT = 'True' == os.environ.get('AA_BLUE_API_ACCOUNT', 'False') REJECT_OLD_APIS = 'True' == os.environ.get('AA_REJECT_OLD_APIS', 'False') REJECT_OLD_APIS_MARGIN = os.environ.get('AA_REJECT_OLD_APIS_MARGIN', 50) -########################## -# Pathfinder Configuration -########################## -PATHFINDER_URL = os.environ.get('AA_PATHFINDER_URL', 'http://pathfinder.yourdomain.com') - ##################### # Alliance Market ##################### MARKET_URL = os.environ.get('AA_MARKET_URL', 'http://yourdomain.com/market') +MARKET_DB = { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'alliance_market', + 'USER': os.environ.get('AA_DB_MARKET_USER', 'allianceserver'), + 'PASSWORD': os.environ.get('AA_DB_MARKET_PASSWORD', 'password'), + 'HOST': os.environ.get('AA_DB_MARKET_HOST', '127.0.0.1'), + 'PORT': os.environ.get('AA_DB_MARKET_PORT', '3306'), +} ##################### # HR Configuration @@ -427,6 +422,18 @@ BROADCAST_SERVICE_NAME = os.environ.get('AA_BROADCAST_SERVICE_NAME', "broadcast" MUMBLE_URL = os.environ.get('AA_MUMBLE_URL', "yourdomain.com") MUMBLE_SERVER_ID = int(os.environ.get('AA_MUMBLE_SERVER_ID', '1')) +###################################### +# PHPBB3 Configuration +###################################### +PHPBB3_DB = { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'alliance_forum', + 'USER': os.environ.get('AA_DB_PHPBB3_USER', 'allianceserver'), + 'PASSWORD': os.environ.get('AA_DB_PHPBB3_PASSWORD', 'password'), + 'HOST': os.environ.get('AA_DB_PHPBB3_HOST', '127.0.0.1'), + 'PORT': os.environ.get('AA_DB_PHPBB3_PORT', '3306'), +} + ###################################### # Teamspeak3 Configuration ###################################### @@ -484,6 +491,28 @@ DISCOURSE_API_KEY = os.environ.get('AA_DISCOURSE_API_KEY', '') ##################################### IPS4_URL = os.environ.get('AA_IPS4_URL', 'http://yourdomain.com/ips4') IPS4_API_KEY = os.environ.get('AA_IPS4_API_KEY', '') +IPS4_DB = { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'alliance_ips4', + 'USER': os.environ.get('AA_DB_IPS4_USER', 'allianceserver'), + 'PASSWORD': os.environ.get('AA_DB_IPS4_PASSWORD', 'password'), + 'HOST': os.environ.get('AA_DB_IPS4_HOST', '127.0.0.1'), + 'PORT': os.environ.get('AA_DB_IPS4_PORT', '3306'), +} + + +###################################### +# SMF Configuration +###################################### +SMF_URL = os.environ.get('AA_SMF_URL', '') +SMF_DB = { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'alliance_smf', + 'USER': os.environ.get('AA_DB_SMF_USER', 'allianceserver'), + 'PASSWORD': os.environ.get('AA_DB_SMF_PASSWORD', 'password'), + 'HOST': os.environ.get('AA_DB_SMF_HOST', '127.0.0.1'), + 'PORT': os.environ.get('AA_DB_SMF_PORT', '3306'), +} ###################################### # Fleet-Up Configuration @@ -597,7 +626,7 @@ LOGGING = { 'level': 'DEBUG', }, 'fleetactivitytracking': { - 'handlers': ['log_file', 'console'], + 'handlers': ['log_file', 'console', 'notifications'], 'level': 'ERROR', }, 'util': { @@ -610,3 +639,13 @@ LOGGING = { }, } } + +# Conditionally add databases only if configured +if ENABLE_AUTH_FORUM or ENABLE_BLUE_FORUM: + DATABASES['phpbb3'] = PHPBB3_DB +if ENABLE_AUTH_SMF or ENABLE_BLUE_SMF: + DATABASES['smf'] = SMF_DB +if ENABLE_AUTH_MARKET or ENABLE_BLUE_MARKET: + DATABASES['market'] = MARKET_DB +if ENABLE_AUTH_IPS4 or ENABLE_BLUE_IPS4: + DATABASES['ips4'] = IPS4_DB diff --git a/alliance_auth/urls.py b/alliance_auth/urls.py index 7c89f56b..57a0f3ce 100755 --- a/alliance_auth/urls.py +++ b/alliance_auth/urls.py @@ -1,299 +1,303 @@ -from django.conf.urls import patterns, include, url +from django.conf.urls import include, url from django.conf.urls.i18n import i18n_patterns from django.utils.translation import ugettext_lazy as _ from django.contrib import admin - -admin.autodiscover() +import django.contrib.auth.views +import authentication.views +import eveonline.views +import services.views +import groupmanagement.views +import optimer.views +import timerboard.views +import corputils.views +import fleetactivitytracking.views +import fleetup.views +import srp.views +import notifications.views +import hrapplications.views +import eve_sso.urls # Functional/Untranslated URL's -urlpatterns = patterns('', - - # Locale - url(r'^i18n/', include('django.conf.urls.i18n')), +urlpatterns = [ + # Locale + url(r'^i18n/', include('django.conf.urls.i18n')), - # Admin urls - url(r'^admin/', include(admin.site.urls)), + # Admin urls + url(r'^admin/', include(admin.site.urls)), - # Index - url(_(r'^$'), 'portal.views.index_view', name='auth_index'), - - # Authentication - url(r'^logout_user/', 'authentication.views.logout_user', name='auth_logout_user'), + # SSO + url (r'^sso/', include(eve_sso.urls, namespace='eve_sso')), + url (r'^sso/login$', authentication.views.sso_login, name='auth_sso_login'), - # Eve Online - url(r'^main_character_change/(\w+)/$', 'eveonline.views.main_character_change', - name='auth_main_character_change'), + # Index + url(_(r'^$'), authentication.views.index_view, name='auth_index'), - # Forum Service Control - url(r'^activate_forum/$', 'services.views.activate_forum', name='auth_activate_forum'), - url(r'^deactivate_forum/$', 'services.views.deactivate_forum', name='auth_deactivate_forum'), - url(r'^reset_forum_password/$', 'services.views.reset_forum_password', - name='auth_reset_forum_password'), - url(r'^set_forum_password/$', 'services.views.set_forum_password', name='auth_set_forum_password'), + # Authentication + url(r'^logout_user/', authentication.views.logout_user, name='auth_logout_user'), - # Jabber Service Control - url(r'^activate_jabber/$', 'services.views.activate_jabber', name='auth_activate_jabber'), - url(r'^deactivate_jabber/$', 'services.views.deactivate_jabber', name='auth_deactivate_jabber'), - url(r'^reset_jabber_password/$', 'services.views.reset_jabber_password', - name='auth_reset_jabber_password'), + # Eve Online + url(r'^main_character_change/(\w+)/$', eveonline.views.main_character_change, + name='auth_main_character_change'), - # Mumble service control - url(r'^activate_mumble/$', 'services.views.activate_mumble', name='auth_activate_mumble'), - url(r'^deactivate_mumble/$', 'services.views.deactivate_mumble', name='auth_deactivate_mumble'), - url(r'^reset_mumble_password/$', 'services.views.reset_mumble_password', - name='auth_reset_mumble_password'), - url(r'^set_mumble_password/$', 'services.views.set_mumble_password', name='auth_set_mumble_password'), + # Forum Service Control + url(r'^activate_forum/$', services.views.activate_forum, name='auth_activate_forum'), + url(r'^deactivate_forum/$', services.views.deactivate_forum, name='auth_deactivate_forum'), + url(r'^reset_forum_password/$', services.views.reset_forum_password, + name='auth_reset_forum_password'), + url(r'^set_forum_password/$', services.views.set_forum_password, name='auth_set_forum_password'), - # Ipboard service control - url(r'^activate_ipboard/$', 'services.views.activate_ipboard_forum', - name='auth_activate_ipboard'), - url(r'^deactivate_ipboard/$', 'services.views.deactivate_ipboard_forum', - name='auth_deactivate_ipboard'), - url(r'^reset_ipboard_password/$', 'services.views.reset_ipboard_password', - name='auth_reset_ipboard_password'), - url(r'^set_ipboard_password/$', 'services.views.set_ipboard_password', name='auth_set_ipboard_password'), + # Jabber Service Control + url(r'^activate_jabber/$', services.views.activate_jabber, name='auth_activate_jabber'), + url(r'^deactivate_jabber/$', services.views.deactivate_jabber, name='auth_deactivate_jabber'), + url(r'^reset_jabber_password/$', services.views.reset_jabber_password, + name='auth_reset_jabber_password'), - # XenForo service control - url(r'^activate_xenforo/$', 'services.views.activate_xenforo_forum', - name='auth_activate_xenforo'), - url(r'^deactivate_xenforo/$', 'services.views.deactivate_xenforo_forum', - name='auth_deactivate_xenforo'), - url(r'^reset_xenforo_password/$', 'services.views.reset_xenforo_password', - name='auth_reset_xenforo_password'), - url(r'^set_xenforo_password/$', 'services.views.set_xenforo_password', name='auth_set_xenforo_password'), + # Mumble service control + url(r'^activate_mumble/$', services.views.activate_mumble, name='auth_activate_mumble'), + url(r'^deactivate_mumble/$', services.views.deactivate_mumble, name='auth_deactivate_mumble'), + url(r'^reset_mumble_password/$', services.views.reset_mumble_password, + name='auth_reset_mumble_password'), + url(r'^set_mumble_password/$', services.views.set_mumble_password, name='auth_set_mumble_password'), - # Teamspeak3 service control - url(r'^activate_teamspeak3/$', 'services.views.activate_teamspeak3', - name='auth_activate_teamspeak3'), - url(r'^deactivate_teamspeak3/$', 'services.views.deactivate_teamspeak3', - name='auth_deactivate_teamspeak3'), - url(r'reset_teamspeak3_perm/$', 'services.views.reset_teamspeak3_perm', - name='auth_reset_teamspeak3_perm'), + # Ipboard service control + url(r'^activate_ipboard/$', services.views.activate_ipboard_forum, + name='auth_activate_ipboard'), + url(r'^deactivate_ipboard/$', services.views.deactivate_ipboard_forum, + name='auth_deactivate_ipboard'), + url(r'^reset_ipboard_password/$', services.views.reset_ipboard_password, + name='auth_reset_ipboard_password'), + url(r'^set_ipboard_password/$', services.views.set_ipboard_password, name='auth_set_ipboard_password'), - # Discord Service Control - url(r'^activate_discord/$', 'services.views.activate_discord', name='auth_activate_discord'), - url(r'^deactivate_discord/$', 'services.views.deactivate_discord', name='auth_deactivate_discord'), - url(r'^reset_discord/$', 'services.views.reset_discord', name='auth_reset_discord'), - url(r'^discord_callback/$', 'services.views.discord_callback', name='auth_discord_callback'), - url(r'^discord_add_bot/$', 'services.views.discord_add_bot', name='auth_discord_add_bot'), - - # Discourse Service Control - url(r'^activate_discourse/$', 'services.views.activate_discourse', name='auth_activate_discourse'), - url(r'^deactivate_discourse/$', 'services.views.deactivate_discourse', name='auth_deactivate_discourse'), + # XenForo service control + url(r'^activate_xenforo/$', services.views.activate_xenforo_forum, + name='auth_activate_xenforo'), + url(r'^deactivate_xenforo/$', services.views.deactivate_xenforo_forum, + name='auth_deactivate_xenforo'), + url(r'^reset_xenforo_password/$', services.views.reset_xenforo_password, + name='auth_reset_xenforo_password'), + url(r'^set_xenforo_password/$', services.views.set_xenforo_password, name='auth_set_xenforo_password'), - # IPS4 Service Control - url(r'^activate_ips4/$', 'services.views.activate_ips4', - name='auth_activate_ips4'), - url(r'^deactivate_ips4/$', 'services.views.deactivate_ips4', - name='auth_deactivate_ips4'), - url(r'^reset_ips4_password/$', 'services.views.reset_ips4_password', - name='auth_reset_ips4_password'), - url(r'^set_ips4_password/$', 'services.views.set_ips4_password', name='auth_set_ips4_password'), + # Teamspeak3 service control + url(r'^activate_teamspeak3/$', services.views.activate_teamspeak3, + name='auth_activate_teamspeak3'), + url(r'^deactivate_teamspeak3/$', services.views.deactivate_teamspeak3, + name='auth_deactivate_teamspeak3'), + url(r'reset_teamspeak3_perm/$', services.views.reset_teamspeak3_perm, + name='auth_reset_teamspeak3_perm'), - # SMF Service Control - url(r'^activate_smf/$', 'services.views.activate_smf', name='auth_activate_smf'), - url(r'^deactivate_smf/$', 'services.views.deactivate_smf', name='auth_deactivate_smf'), - url(r'^reset_smf_password/$', 'services.views.reset_smf_password', - name='auth_reset_smf_password'), - url(r'^set_smf_password/$', 'services.views.set_smf_password', name='auth_set_smf_password'), + # Discord Service Control + url(r'^activate_discord/$', services.views.activate_discord, name='auth_activate_discord'), + url(r'^deactivate_discord/$', services.views.deactivate_discord, name='auth_deactivate_discord'), + url(r'^reset_discord/$', services.views.reset_discord, name='auth_reset_discord'), + url(r'^discord_callback/$', services.views.discord_callback, name='auth_discord_callback'), + url(r'^discord_add_bot/$', services.views.discord_add_bot, name='auth_discord_add_bot'), - # Alliance Market Control - url(r'^activate_market/$', 'services.views.activate_market', name='auth_activate_market'), - url(r'^deactivate_market/$', 'services.views.deactivate_market', name='auth_deactivate_market'), - url(r'^reset_market_password/$', 'services.views.reset_market_password', - name='auth_reset_market_password'), - url(r'^set_market_password/$', 'services.views.set_market_password', name='auth_set_market_password'), + # Discourse Service Control + url(r'^activate_discourse/$', services.views.activate_discourse, name='auth_activate_discourse'), + url(r'^deactivate_discourse/$', services.views.deactivate_discourse, name='auth_deactivate_discourse'), - # Pathfinder Control - url(r'^activate_pathfinder/$', 'services.views.activate_pathfinder', name='auth_activate_pathfinder'), - url(r'^deactivate_pathfinder/$', 'services.views.deactivate_pathfinder', name='auth_deactivate_pathfinder'), - url(r'^reset_pathfinder_password/$', 'services.views.reset_pathfinder_password', - name='auth_reset_pathfinder_password'), - url(r'^set_pathfinder_password/$', 'services.views.set_pathfinder_password', name='auth_set_pathfinder_password'), + # IPS4 Service Control + url(r'^activate_ips4/$', services.views.activate_ips4, + name='auth_activate_ips4'), + url(r'^deactivate_ips4/$', services.views.deactivate_ips4, + name='auth_deactivate_ips4'), + url(r'^reset_ips4_password/$', services.views.reset_ips4_password, + name='auth_reset_ips4_password'), + url(r'^set_ips4_password/$', services.views.set_ips4_password, name='auth_set_ips4_password'), - # SRP URLS - url(r'^srp_fleet_remove/(\w+)$', 'srp.views.srp_fleet_remove', name='auth_srp_fleet_remove'), - url(r'^srp_fleet_disable/(\w+)$', 'srp.views.srp_fleet_disable', name='auth_srp_fleet_disable'), - url(r'^srp_fleet_enable/(\w+)$', 'srp.views.srp_fleet_enable', name='auth_srp_fleet_enable'), - url(r'^srp_fleet_mark_completed/(\w+)', 'srp.views.srp_fleet_mark_completed', - name='auth_srp_fleet_mark_completed'), - url(r'^srp_fleet_mark_uncompleted/(\w+)', 'srp.views.srp_fleet_mark_uncompleted', - name='auth_srp_fleet_mark_uncompleted'), - url(r'^srp_request_remove/(\w+)', 'srp.views.srp_request_remove', - name="auth_srp_request_remove"), - url(r'srp_request_approve/(\w+)', 'srp.views.srp_request_approve', - name='auth_srp_request_approve'), - url(r'srp_request_reject/(\w+)', 'srp.views.srp_request_reject', name='auth_srp_request_reject'), + # SMF Service Control + url(r'^activate_smf/$', services.views.activate_smf, name='auth_activate_smf'), + url(r'^deactivate_smf/$', services.views.deactivate_smf, name='auth_deactivate_smf'), + url(r'^reset_smf_password/$', services.views.reset_smf_password, + name='auth_reset_smf_password'), + url(r'^set_smf_password/$', services.views.set_smf_password, name='auth_set_smf_password'), - # Notifications - url(r'^remove_notifications/(\w+)/$', 'notifications.views.remove_notification', name='auth_remove_notification'), -) + # Alliance Market Control + url(r'^activate_market/$', services.views.activate_market, name='auth_activate_market'), + url(r'^deactivate_market/$', services.views.deactivate_market, name='auth_deactivate_market'), + url(r'^reset_market_password/$', services.views.reset_market_password, + name='auth_reset_market_password'), + url(r'^set_market_password/$', services.views.set_market_password, name='auth_set_market_password'), + + # SRP URLS + url(r'^srp_fleet_remove/(\w+)$', srp.views.srp_fleet_remove, name='auth_srp_fleet_remove'), + url(r'^srp_fleet_disable/(\w+)$', srp.views.srp_fleet_disable, name='auth_srp_fleet_disable'), + url(r'^srp_fleet_enable/(\w+)$', srp.views.srp_fleet_enable, name='auth_srp_fleet_enable'), + url(r'^srp_fleet_mark_completed/(\w+)', srp.views.srp_fleet_mark_completed, + name='auth_srp_fleet_mark_completed'), + url(r'^srp_fleet_mark_uncompleted/(\w+)', srp.views.srp_fleet_mark_uncompleted, + name='auth_srp_fleet_mark_uncompleted'), + url(r'^srp_request_remove/(\w+)', srp.views.srp_request_remove, + name="auth_srp_request_remove"), + url(r'srp_request_approve/(\w+)', srp.views.srp_request_approve, + name='auth_srp_request_approve'), + url(r'srp_request_reject/(\w+)', srp.views.srp_request_reject, name='auth_srp_request_reject'), + + # Notifications + url(r'^remove_notifications/(\w+)/$', notifications.views.remove_notification, name='auth_remove_notification'), + url(r'^notifications/mark_all_read/$', notifications.views.mark_all_read, name='auth_mark_all_notifications_read'), + url(r'^notifications/delete_all_read/$', notifications.views.delete_all_read, + name='auth_delete_all_read_notifications'), +] # User viewed/translated URLS -urlpatterns += i18n_patterns('', +urlpatterns += i18n_patterns( - #corputils - url(r'^corputils/$', 'corputils.views.corp_member_view', name='auth_corputils'), - url(r'^corputils/(?P[0-9]+)/$', 'corputils.views.corp_member_view'), - url(r'^corputils/(?P[0-9]+)/(?P[0-9]+)/(?P[0-9]+)/$', 'corputils.views.corp_member_view', name='auth_corputils_month'), - url(r'^corputils/search/$', 'corputils.views.corputils_search', name="auth_corputils_search"), - url(r'^corputils/search/(?P[0-9]+)/$', 'corputils.views.corputils_search'), + # corputils + url(r'^corputils/$', corputils.views.corp_member_view, name='auth_corputils'), + url(r'^corputils/(?P[0-9]+)/$', corputils.views.corp_member_view, name='auth_corputils_corp_view'), + url(r'^corputils/(?P[0-9]+)/(?P[0-9]+)/(?P[0-9]+)/$', corputils.views.corp_member_view, + name='auth_corputils_month'), + url(r'^corputils/search/$', corputils.views.corputils_search, name="auth_corputils_search"), + url(r'^corputils/search/(?P[0-9]+)/$', corputils.views.corputils_search, name='auth_corputils_search_corp'), - # FLEET FITTINGS - url(r'^fits/$', 'services.views.fleet_fits', name='auth_fleet_fits'), - - #Fleetup - url(r'^fleetup/$', 'fleetup.views.fleetup_view', name='auth_fleetup_view'), - url(r'^fleetup/fittings/$', 'fleetup.views.fleetup_fittings', name='auth_fleetup_fittings'), - url(r'^fleetup/fittings/(?P[0-9]+)/$', 'fleetup.views.fleetup_fitting'), - url(r'^fleetup/doctrines/$', 'fleetup.views.fleetup_doctrines', name='auth_fleetup_doctrines'), - url(r'^fleetup/characters/$', 'fleetup.views.fleetup_characters', name='auth_fleetup_characters'), - url(r'^fleetup/doctrines/(?P[0-9]+)/$', 'fleetup.views.fleetup_doctrine'), + # Fleetup + url(r'^fleetup/$', fleetup.views.fleetup_view, name='auth_fleetup_view'), + url(r'^fleetup/fittings/$', fleetup.views.fleetup_fittings, name='auth_fleetup_fittings'), + url(r'^fleetup/fittings/(?P[0-9]+)/$', fleetup.views.fleetup_fitting, name='auth_fleetup_fitting'), + url(r'^fleetup/doctrines/$', fleetup.views.fleetup_doctrines, name='auth_fleetup_doctrines'), + url(r'^fleetup/characters/$', fleetup.views.fleetup_characters, name='auth_fleetup_characters'), + url(r'^fleetup/doctrines/(?P[0-9]+)/$', fleetup.views.fleetup_doctrine, name='auth_fleetup_doctrine'), - # Authentication - url(_(r'^login_user/'), 'authentication.views.login_user', name='auth_login_user'), - url(_(r'^register_user/'), 'registration.views.register_user_view', name='auth_register_user'), - - url(_(r'^user/password/$'), 'django.contrib.auth.views.password_change', name='password_change'), - url(_(r'^user/password/done/$'), 'django.contrib.auth.views.password_change_done', - name='password_change_done'), - url(_(r'^user/password/reset/$'), 'django.contrib.auth.views.password_reset', - name='password_reset'), - url(_(r'^user/password/password/reset/done/$'), 'django.contrib.auth.views.password_reset_done', - name='password_reset_done'), - url(_(r'^user/password/reset/complete/$'), 'django.contrib.auth.views.password_reset_complete', - name='password_reset_complete'), - url(_(r'^user/password/reset/confirm/(?P[0-9A-Za-z_\-]+)/(?P.+)/$'), - 'django.contrib.auth.views.password_reset_confirm', name='password_reset_confirm'), - - # Portal Urls - url(_(r'^dashboard/$'), 'portal.views.dashboard_view', name='auth_dashboard'), - url(_(r'^help/$'), 'portal.views.help_view', name='auth_help'), - - # Eveonline Urls - url(_(r'^add_api_key/'), 'eveonline.views.add_api_key', name='auth_add_api_key'), - url(_(r'^api_key_management/'), 'eveonline.views.api_key_management_view', - name='auth_api_key_management'), - url(_(r'^refresh_api_pair/([0-9]+)/$'), 'eveonline.views.user_refresh_api', name='auth_user_refresh_api'), - url(_(r'^delete_api_pair/(\w+)/$'), 'eveonline.views.api_key_removal', name='auth_api_key_removal'), - url(_(r'^characters/'), 'eveonline.views.characters_view', name='auth_characters'), + # Authentication + url(_(r'^login_user/'), authentication.views.login_user, name='auth_login_user'), + url(_(r'^register_user/'), authentication.views.register_user_view, name='auth_register_user'), - # Group management - url(_(r'^groups/'), 'groupmanagement.views.groups_view', name='auth_groups'), - url(_(r'^group/management/'), 'groupmanagement.views.group_management', - name='auth_group_management'), - url(_(r'^group/request_add/(\w+)'), 'groupmanagement.views.group_request_add', - name='auth_group_request_add'), - url(_(r'^group/request/accept/(\w+)'), 'groupmanagement.views.group_accept_request', - name='auth_group_accept_request'), - url(_(r'^group/request/reject/(\w+)'), 'groupmanagement.views.group_reject_request', - name='auth_group_reject_request'), + url(_(r'^user/password/$'), django.contrib.auth.views.password_change, name='password_change'), + url(_(r'^user/password/done/$'), django.contrib.auth.views.password_change_done, + name='password_change_done'), + url(_(r'^user/password/reset/$'), django.contrib.auth.views.password_reset, + name='password_reset'), + url(_(r'^user/password/password/reset/done/$'), django.contrib.auth.views.password_reset_done, + name='password_reset_done'), + url(_(r'^user/password/reset/complete/$'), django.contrib.auth.views.password_reset_complete, + name='password_reset_complete'), + url(_(r'^user/password/reset/confirm/(?P[0-9A-Za-z_\-]+)/(?P.+)/$'), + django.contrib.auth.views.password_reset_confirm, name='password_reset_confirm'), - url(_(r'^group/request_leave/(\w+)'), 'groupmanagement.views.group_request_leave', - name='auth_group_request_leave'), - url(_(r'group/leave_request/accept/(\w+)'), 'groupmanagement.views.group_leave_accept_request', - name='auth_group_leave_accept_request'), - url(_(r'^group/leave_request/reject/(\w+)'), 'groupmanagement.views.group_leave_reject_request', - name='auth_group_leave_reject_request'), + # Portal Urls + url(_(r'^dashboard/$'), authentication.views.dashboard_view, name='auth_dashboard'), + url(_(r'^help/$'), authentication.views.help_view, name='auth_help'), - # HR Application Management - url(_(r'^hr_application_management/'), 'hrapplications.views.hr_application_management_view', - name="auth_hrapplications_view"), - url(_(r'^hr_application_create/$'), 'hrapplications.views.hr_application_create_view', - name="auth_hrapplication_create_view"), - url(_(r'^hr_application_create/(\d+)'), 'hrapplications.views.hr_application_create_view', - name="auth_hrapplication_create_view"), - url(_(r'^hr_application_remove/(\w+)'), 'hrapplications.views.hr_application_remove', - name="auth_hrapplication_remove"), - url(_(r'hr_application_view/(\w+)'), 'hrapplications.views.hr_application_view', - name="auth_hrapplication_view"), - url(_(r'hr_application_personal_view/(\w+)'), 'hrapplications.views.hr_application_personal_view', - name="auth_hrapplication_personal_view"), - url(_(r'hr_application_personal_removal/(\w+)'), - 'hrapplications.views.hr_application_personal_removal', - name="auth_hrapplication_personal_removal"), - url(_(r'hr_application_approve/(\w+)'), 'hrapplications.views.hr_application_approve', - name="auth_hrapplication_approve"), - url(_(r'hr_application_reject/(\w+)'), 'hrapplications.views.hr_application_reject', - name="auth_hrapplication_reject"), - url(_(r'hr_application_search/'), 'hrapplications.views.hr_application_search', - name="auth_hrapplication_search"), - url(_(r'hr_mark_in_progress/(\w+)'), 'hrapplications.views.hr_application_mark_in_progress', - name="auth_hrapplication_mark_in_progress"), - - # Fleet Operations Timers - url(_(r'^optimer/$'), 'optimer.views.optimer_view', name='auth_optimer_view'), - url(_(r'^add_optimer/$'), 'optimer.views.add_optimer_view', name='auth_add_optimer_view'), - url(_(r'^remove_optimer/(\w+)'), 'optimer.views.remove_optimer', name='auth_remove_optimer'), - url(_(r'^edit_optimer/(\w+)$'), 'optimer.views.edit_optimer', name='auth_edit_optimer'), + # Eveonline Urls + url(_(r'^add_api_key/'), eveonline.views.add_api_key, name='auth_add_api_key'), + url(_(r'^api_key_management/'), eveonline.views.api_key_management_view, + name='auth_api_key_management'), + url(_(r'^refresh_api_pair/([0-9]+)/$'), eveonline.views.user_refresh_api, name='auth_user_refresh_api'), + url(_(r'^delete_api_pair/(\w+)/$'), eveonline.views.api_key_removal, name='auth_api_key_removal'), + url(_(r'^characters/'), eveonline.views.characters_view, name='auth_characters'), - # Service Urls - url(_(r'^services/$'), 'services.views.services_view', name='auth_services'), - url(_(r'^services/jabber_broadcast/$'), 'services.views.jabber_broadcast_view', - name='auth_jabber_broadcast_view'), + # Group management + url(_(r'^groups/'), groupmanagement.views.groups_view, name='auth_groups'), + url(_(r'^group/management/'), groupmanagement.views.group_management, + name='auth_group_management'), + url(_(r'^group/request_add/(\w+)'), groupmanagement.views.group_request_add, + name='auth_group_request_add'), + url(_(r'^group/request/accept/(\w+)'), groupmanagement.views.group_accept_request, + name='auth_group_accept_request'), + url(_(r'^group/request/reject/(\w+)'), groupmanagement.views.group_reject_request, + name='auth_group_reject_request'), - #Teamspeak Urls - url(r'verify_teamspeak3/$', 'services.views.verify_teamspeak3', name='auth_verify_teamspeak3'), - - #corputils - url(_(r'^corputils/$'), 'corputils.views.corp_member_view', name='auth_corputils'), - url(_(r'^corputils/(?P[0-9]+)/$'), 'corputils.views.corp_member_view'), - url(_(r'^corputils/search/$'), 'corputils.views.corputils_search', name="auth_corputils_search"), - url(_(r'^corputils/search/(?P[0-9]+)/$'), 'corputils.views.corputils_search'), - - # Timer URLS - url(_(r'^timers/$'), 'timerboard.views.timer_view', name='auth_timer_view'), - url(_(r'^add_timer/$'), 'timerboard.views.add_timer_view', name='auth_add_timer_view'), - url(_(r'^remove_timer/(\w+)'), 'timerboard.views.remove_timer', name='auth_remove_timer'), - url(_(r'^edit_timer/(\w+)$'), 'timerboard.views.edit_timer', name='auth_edit_timer'), - - # Sig Tracker - url(_(r'^sigtracker/$'), 'sigtracker.views.sigtracker_view', name='auth_signature_view'), - url(_(r'^add_signature/$'), 'sigtracker.views.add_signature_view', name='auth_add_signature_view'), - url(_(r'^remove_signature/(\w+)'), 'sigtracker.views.remove_signature', name='auth_remove_signature'), - url(_(r'^edit_signature/(\w+)$'), 'sigtracker.views.edit_signature', name='auth_edit_signature'), - - #SRP URLS - url(_(r'^srp/$'), 'srp.views.srp_management', name='auth_srp_management_view'), - url(_(r'^srp_all/$'), 'srp.views.srp_management_all', name='auth_srp_management_all_view'), - url(_(r'^srp_fleet_view/(\w+)$'), 'srp.views.srp_fleet_view', name='auth_srp_fleet_view'), - url(_(r'^srp_fleet_add_view/$'), 'srp.views.srp_fleet_add_view', name='auth_srp_fleet_add_view'), - url(_(r'^srp_fleet_edit/(\w+)$'), 'srp.views.srp_fleet_edit_view', name='auth_srp_fleet_edit_view'), - url(_(r'^srp_request/(\w+)'), 'srp.views.srp_request_view', name='auth_srp_request_view'), - url(_(r'srp_request_amount_update/(\w+)'), 'srp.views.srp_request_update_amount_view', - name="auth_srp_request_update_amount_view"), - - # Tools - url(_(r'^tool/fleet_formatter_tool/$'), 'services.views.fleet_formatter_view', - name='auth_fleet_format_tool_view'), + url(_(r'^group/request_leave/(\w+)'), groupmanagement.views.group_request_leave, + name='auth_group_request_leave'), + url(_(r'group/leave_request/accept/(\w+)'), groupmanagement.views.group_leave_accept_request, + name='auth_group_leave_accept_request'), + url(_(r'^group/leave_request/reject/(\w+)'), groupmanagement.views.group_leave_reject_request, + name='auth_group_leave_reject_request'), - # Notifications - url(_(r'^notifications/$'), 'notifications.views.notification_list', name='auth_notification_list'), - url(_(r'^notifications/(\w+)/$'), 'notifications.views.notification_view', name='auth_notification_view'), - - #Jabber - url(_(r'^set_jabber_password/$'), 'services.views.set_jabber_password', name='auth_set_jabber_password'), - - # FLEET FITTINGS - url(_(r'^fits/$'), 'services.views.fleet_fits', name='auth_fleet_fits'), - - # FleetActivityTracking (FAT) - url(r'^fat/$', 'fleetactivitytracking.views.fatlink_view', name='auth_fatlink_view'), - url(r'^fat/statistics/$', 'fleetactivitytracking.views.fatlink_statistics_view', name='auth_fatlink_view_statistics'), - url(r'^fat/statistics/(?P[0-9]+)/(?P[0-9]+)/$', 'fleetactivitytracking.views.fatlink_statistics_view', name='auth_fatlink_view_statistics_month'), - url(r'^fat/user/statistics/$', 'fleetactivitytracking.views.fatlink_personal_statistics_view', name='auth_fatlink_view_personal_statistics'), - url(r'^fat/user/statistics/(?P[0-9]+)/$', 'fleetactivitytracking.views.fatlink_personal_statistics_view', name='auth_fatlink_view_personal_statistics_year'), - url(r'^fat/user/statistics/(?P[0-9]+)/(?P[0-9]+)/$', 'fleetactivitytracking.views.fatlink_monthly_personal_statistics_view', - name='auth_fatlink_view_personal_statistics_month'), - url(r'^fat/user/(?P[0-9]+)/statistics/(?P[0-9]+)/(?P[0-9]+)/$', 'fleetactivitytracking.views.fatlink_monthly_personal_statistics_view', - name='auth_fatlink_view_user_statistics_month'), - url(r'^fat/create/$', 'fleetactivitytracking.views.create_fatlink_view', name='auth_create_fatlink_view'), - url(r'^fat/modify/$', 'fleetactivitytracking.views.modify_fatlink_view', name='auth_modify_fatlink_view'), - url(r'^fat/modify/(?P[a-zA-Z0-9_-]+)/([a-z0-9_-]+)$', - 'fleetactivitytracking.views.modify_fatlink_view'), - url(r'^fat/link/$', 'fleetactivitytracking.views.fatlink_view', name='auth_click_fatlink_view'), - url(r'^fat/link/(?P[a-zA-Z0-9]+)/(?P[a-z0-9_-]+)/$', - 'fleetactivitytracking.views.click_fatlink_view'), + # HR Application Management + url(_(r'^hr_application_management/'), hrapplications.views.hr_application_management_view, + name="auth_hrapplications_view"), + url(_(r'^hr_application_create/$'), hrapplications.views.hr_application_create_view, + name="auth_hrapplication_create_view"), + url(_(r'^hr_application_create/(\d+)'), hrapplications.views.hr_application_create_view, + name="auth_hrapplication_create_view"), + url(_(r'^hr_application_remove/(\w+)'), hrapplications.views.hr_application_remove, + name="auth_hrapplication_remove"), + url(_(r'hr_application_view/(\w+)'), hrapplications.views.hr_application_view, + name="auth_hrapplication_view"), + url(_(r'hr_application_personal_view/(\w+)'), hrapplications.views.hr_application_personal_view, + name="auth_hrapplication_personal_view"), + url(_(r'hr_application_personal_removal/(\w+)'), + hrapplications.views.hr_application_personal_removal, + name="auth_hrapplication_personal_removal"), + url(_(r'hr_application_approve/(\w+)'), hrapplications.views.hr_application_approve, + name="auth_hrapplication_approve"), + url(_(r'hr_application_reject/(\w+)'), hrapplications.views.hr_application_reject, + name="auth_hrapplication_reject"), + url(_(r'hr_application_search/'), hrapplications.views.hr_application_search, + name="auth_hrapplication_search"), + url(_(r'hr_mark_in_progress/(\w+)'), hrapplications.views.hr_application_mark_in_progress, + name="auth_hrapplication_mark_in_progress"), + + # Fleet Operations Timers + url(_(r'^optimer/$'), optimer.views.optimer_view, name='auth_optimer_view'), + url(_(r'^add_optimer/$'), optimer.views.add_optimer_view, name='auth_add_optimer_view'), + url(_(r'^remove_optimer/(\w+)'), optimer.views.remove_optimer, name='auth_remove_optimer'), + url(_(r'^edit_optimer/(\w+)$'), optimer.views.edit_optimer, name='auth_edit_optimer'), + + # Service Urls + url(_(r'^services/$'), services.views.services_view, name='auth_services'), + url(_(r'^services/jabber_broadcast/$'), services.views.jabber_broadcast_view, + name='auth_jabber_broadcast_view'), + + # Teamspeak Urls + url(r'verify_teamspeak3/$', services.views.verify_teamspeak3, name='auth_verify_teamspeak3'), + + # corputils + url(_(r'^corputils/$'), corputils.views.corp_member_view, name='auth_corputils'), + url(_(r'^corputils/(?P[0-9]+)/$'), corputils.views.corp_member_view, name='auth_corputils_corp_view'), + url(_(r'^corputils/search/$'), corputils.views.corputils_search, name="auth_corputils_search"), + url(_(r'^corputils/search/(?P[0-9]+)/$'), corputils.views.corputils_search, name='auth_corputils_search_corp'), + + # Timer URLS + url(_(r'^timers/$'), timerboard.views.timer_view, name='auth_timer_view'), + url(_(r'^add_timer/$'), timerboard.views.add_timer_view, name='auth_add_timer_view'), + url(_(r'^remove_timer/(\w+)'), timerboard.views.remove_timer, name='auth_remove_timer'), + url(_(r'^edit_timer/(\w+)$'), timerboard.views.edit_timer, name='auth_edit_timer'), + + # SRP URLS + url(_(r'^srp/$'), srp.views.srp_management, name='auth_srp_management_view'), + url(_(r'^srp_all/$'), srp.views.srp_management_all, name='auth_srp_management_all_view'), + url(_(r'^srp_fleet_view/(\w+)$'), srp.views.srp_fleet_view, name='auth_srp_fleet_view'), + url(_(r'^srp_fleet_add_view/$'), srp.views.srp_fleet_add_view, name='auth_srp_fleet_add_view'), + url(_(r'^srp_fleet_edit/(\w+)$'), srp.views.srp_fleet_edit_view, name='auth_srp_fleet_edit_view'), + url(_(r'^srp_request/(\w+)'), srp.views.srp_request_view, name='auth_srp_request_view'), + url(_(r'srp_request_amount_update/(\w+)'), srp.views.srp_request_update_amount_view, + name="auth_srp_request_update_amount_view"), + + # Tools + url(_(r'^tool/fleet_formatter_tool/$'), services.views.fleet_formatter_view, + name='auth_fleet_format_tool_view'), + + # Notifications + url(_(r'^notifications/$'), notifications.views.notification_list, name='auth_notification_list'), + url(_(r'^notifications/(\w+)/$'), notifications.views.notification_view, name='auth_notification_view'), + + # Jabber + url(_(r'^set_jabber_password/$'), services.views.set_jabber_password, name='auth_set_jabber_password'), + + # FleetActivityTracking (FAT) + url(r'^fat/$', fleetactivitytracking.views.fatlink_view, name='auth_fatlink_view'), + url(r'^fat/statistics/$', fleetactivitytracking.views.fatlink_statistics_view, name='auth_fatlink_view_statistics'), + url(r'^fat/statistics/(?P[0-9]+)/(?P[0-9]+)/$', fleetactivitytracking.views.fatlink_statistics_view, + name='auth_fatlink_view_statistics_month'), + url(r'^fat/user/statistics/$', fleetactivitytracking.views.fatlink_personal_statistics_view, + name='auth_fatlink_view_personal_statistics'), + url(r'^fat/user/statistics/(?P[0-9]+)/$', fleetactivitytracking.views.fatlink_personal_statistics_view, + name='auth_fatlink_view_personal_statistics_year'), + url(r'^fat/user/statistics/(?P[0-9]+)/(?P[0-9]+)/$', + fleetactivitytracking.views.fatlink_monthly_personal_statistics_view, + name='auth_fatlink_view_personal_statistics_month'), + url(r'^fat/user/(?P[0-9]+)/statistics/(?P[0-9]+)/(?P[0-9]+)/$', + fleetactivitytracking.views.fatlink_monthly_personal_statistics_view, + name='auth_fatlink_view_user_statistics_month'), + url(r'^fat/create/$', fleetactivitytracking.views.create_fatlink_view, name='auth_create_fatlink_view'), + url(r'^fat/modify/$', fleetactivitytracking.views.modify_fatlink_view, name='auth_modify_fatlink_view'), + url(r'^fat/modify/(?P[a-zA-Z0-9_-]+)/([a-z0-9_-]+)$', + fleetactivitytracking.views.modify_fatlink_view), + url(r'^fat/link/$', fleetactivitytracking.views.fatlink_view, name='auth_click_fatlink_view'), + url(r'^fat/link/(?P[a-zA-Z0-9]+)/(?P[a-z0-9_-]+)/$', + fleetactivitytracking.views.click_fatlink_view), ) - diff --git a/alliance_auth/wsgi.py b/alliance_auth/wsgi.py index cd1742c0..a5087167 100644 --- a/alliance_auth/wsgi.py +++ b/alliance_auth/wsgi.py @@ -8,14 +8,13 @@ https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/ """ import os +from django.core.wsgi import get_wsgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "alliance_auth.settings") -from django.core.wsgi import get_wsgi_application - -# virtualenv wrapper -#activate_env=os.path.join(os.path.dirname(os.path.abspath(__file__)), 'env/bin/activate_this.py') -#execfile(activate_env, dict(__file__=activate_env)) +# virtualenv wrapper, uncomment below to activate +# activate_env=os.path.join(os.path.dirname(os.path.abspath(__file__)), 'env/bin/activate_this.py') +# execfile(activate_env, dict(__file__=activate_env)) application = get_wsgi_application() diff --git a/authentication/__init__.py b/authentication/__init__.py index e69de29b..8c013e8e 100644 --- a/authentication/__init__.py +++ b/authentication/__init__.py @@ -0,0 +1,2 @@ +from __future__ import unicode_literals +default_app_config = 'authentication.apps.AuthenticationConfig' diff --git a/authentication/admin.py b/authentication/admin.py index 5c40a0d5..dc41e4f8 100644 --- a/authentication/admin.py +++ b/authentication/admin.py @@ -1,7 +1,146 @@ +from __future__ import unicode_literals + from django.contrib import admin -from models import AuthServicesInfo +from authentication.models import AuthServicesInfo +from eveonline.models import EveCharacter +from services.tasks import update_jabber_groups +from services.tasks import update_mumble_groups +from services.tasks import update_forum_groups +from services.tasks import update_ipboard_groups +from services.tasks import update_smf_groups +from services.tasks import update_teamspeak3_groups +from services.tasks import update_discord_groups +from services.tasks import update_discord_nickname +from services.tasks import update_discourse_groups -# Register your models here. -admin.site.register(AuthServicesInfo) \ No newline at end of file +@admin.register(AuthServicesInfo) +class AuthServicesInfoManager(admin.ModelAdmin): + @staticmethod + def main_character(obj): + if obj.main_char_id: + try: + return EveCharacter.objects.get(character_id=obj.main_char_id) + except EveCharacter.DoesNotExist: + pass + return None + + def sync_jabber(self, request, queryset): + count = 0 + for a in queryset: # queryset filtering doesn't work here? + if a.jabber_username != "": + update_jabber_groups.delay(a.user.pk) + count += 1 + self.message_user(request, "%s jabber accounts queued for group sync." % count) + + sync_jabber.short_description = "Sync groups for selected jabber accounts" + + def sync_mumble(self, request, queryset): + count = 0 + for a in queryset: + if a.mumble_username != "": + update_mumble_groups.delay(a.user.pk) + count += 1 + self.message_user(request, "%s mumble accounts queued for group sync." % count) + + sync_mumble.short_description = "Sync groups for selected mumble accounts" + + def sync_forum(self, request, queryset): + count = 0 + for a in queryset: + if a.forum_username != "": + update_forum_groups.delay(a.user.pk) + count += 1 + self.message_user(request, "%s forum accounts queued for group sync." % count) + + sync_forum.short_description = "Sync groups for selected forum accounts" + + def sync_ipboard(self, request, queryset): + count = 0 + for a in queryset: + if a.ipboard_username != "": + update_ipboard_groups.delay(a.user.pk) + count += 1 + self.message_user(request, "%s ipboard accounts queued for group sync." % count) + + sync_ipboard.short_description = "Sync groups for selected ipboard accounts" + + def sync_smf(self, request, queryset): + count = 0 + for a in queryset: + if a.smf_username != "": + update_smf_groups.delay(a.user.pk) + count += 1 + self.message_user(request, "%s smf accounts queued for group sync." % count) + + sync_smf.short_description = "Sync groups for selected smf accounts" + + def sync_teamspeak(self, request, queryset): + count = 0 + for a in queryset: + if a.teamspeak3_uid != "": + update_teamspeak3_groups.delay(a.user.pk) + count += 1 + self.message_user(request, "%s teamspeak accounts queued for group sync." % count) + + sync_teamspeak.short_description = "Sync groups for selected teamspeak accounts" + + def sync_discord(self, request, queryset): + count = 0 + for a in queryset: + if a.discord_uid != "": + update_discord_groups.delay(a.user.pk) + count += 1 + self.message_user(request, "%s discord accounts queued for group sync." % count) + + sync_discord.short_description = "Sync groups for selected discord accounts" + + def sync_discourse(self, request, queryset): + count = 0 + for a in queryset: + if a.discourse_username != "": + update_discourse_groups.delay(a.user.pk) + count += 1 + self.message_user(request, "%s discourse accounts queued for group sync." % count) + + sync_discourse.short_description = "Sync groups for selected discourse accounts" + + def sync_nicknames(self, request, queryset): + count = 0 + for a in queryset: + if a.discord_uid != "": + update_discord_nickname(a.user.pk) + count += 1 + self.message_user(request, "%s discord accounts queued for nickname sync." % count) + + sync_nicknames.short_description = "Sync nicknames for selected discord accounts" + + actions = [ + 'sync_jabber', + 'sync_mumble', + 'sync_forum', + 'sync_ipboard', + 'sync_smf', + 'sync_teamspeak', + 'sync_discord', + 'sync_discourse', + 'sync_nicknames', + ] + + search_fields = [ + 'user__username', + 'ipboard_username', + 'xenforo_username', + 'forum_username', + 'jabber_username', + 'mumble_username', + 'teamspeak3_uid', + 'discord_uid', + 'discourse_username', + 'ips4_username', + 'smf_username', + 'market_username', + 'main_char_id', + ] + list_display = ('user', 'main_character') diff --git a/authentication/apps.py b/authentication/apps.py new file mode 100644 index 00000000..7fb56f6e --- /dev/null +++ b/authentication/apps.py @@ -0,0 +1,10 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class AuthenticationConfig(AppConfig): + name = 'authentication' + + def ready(self): + import authentication.signals diff --git a/authentication/context_processors.py b/authentication/context_processors.py new file mode 100644 index 00000000..d403df83 --- /dev/null +++ b/authentication/context_processors.py @@ -0,0 +1,25 @@ +from __future__ import unicode_literals +from authentication.models import AuthServicesInfo +from authentication.states import NONE_STATE, BLUE_STATE, MEMBER_STATE +from django.conf import settings + + +def membership_state(request): + if request.user.is_authenticated: + auth = AuthServicesInfo.objects.get_or_create(user=request.user)[0] + return {'STATE': auth.state} + return {'STATE': NONE_STATE} + + +def states(request): + return { + 'BLUE_STATE': BLUE_STATE, + 'MEMBER_STATE': MEMBER_STATE, + 'NONE_STATE': NONE_STATE, + 'MEMBER_BLUE_STATE': [MEMBER_STATE, BLUE_STATE], + } + +def sso(request): + return { + 'EVE_SSO_CALLBACK_URL': settings.EVE_SSO_CALLBACK_URL, + } diff --git a/authentication/decorators.py b/authentication/decorators.py new file mode 100644 index 00000000..1d3167cb --- /dev/null +++ b/authentication/decorators.py @@ -0,0 +1,33 @@ +from __future__ import unicode_literals +from django.contrib.auth.decorators import user_passes_test +from authentication.models import AuthServicesInfo +from authentication.states import MEMBER_STATE, BLUE_STATE, NONE_STATE +from django.conf import settings + + +def _state_required(states, *args, **kwargs): + def test_func(user): + if user.is_superuser and settings.SUPERUSER_STATE_BYPASS: + return True + if user.is_authenticated: + auth = AuthServicesInfo.objects.get_or_create(user=user)[0] + return auth.state in states + return False + + return user_passes_test(test_func, *args, **kwargs) + + +def members(*args, **kwargs): + return _state_required([MEMBER_STATE], *args, **kwargs) + + +def blues(*args, **kwargs): + return _state_required([BLUE_STATE], *args, **kwargs) + + +def members_and_blues(*args, **kwargs): + return _state_required([MEMBER_STATE, BLUE_STATE], *args, **kwargs) + + +def none_state(*args, **kwargs): + return _state_required([NONE_STATE], *args, **kwargs) diff --git a/authentication/forms.py b/authentication/forms.py index 3774277b..76aa3771 100644 --- a/authentication/forms.py +++ b/authentication/forms.py @@ -1,7 +1,42 @@ +from __future__ import unicode_literals from django import forms from django.utils.translation import ugettext_lazy as _ +from django.contrib.auth.models import User +import re class LoginForm(forms.Form): username = forms.CharField(label=_('Username'), max_length=32, required=True) - password = forms.CharField(label=_('Password'), widget=forms.PasswordInput()) \ No newline at end of file + password = forms.CharField(label=_('Password'), widget=forms.PasswordInput()) + + +class RegistrationForm(forms.Form): + username = forms.CharField(label=_('Username'), max_length=30, required=True) + password = forms.CharField(label=_('Password'), widget=forms.PasswordInput(), required=True) + password_again = forms.CharField(label=_('Password Again'), widget=forms.PasswordInput(), required=True) + email = forms.CharField(label=_('Email'), max_length=254, required=True) + email_again = forms.CharField(label=_('Email Again'), max_length=254, required=True) + + def clean(self): + if ' ' in self.cleaned_data['username']: + raise forms.ValidationError('Username cannot contain a space') + + # We attempt to get the user object if we succeed we know email as been used + try: + User.objects.get(email=self.cleaned_data['email']) + raise forms.ValidationError('Email as already been used') + except User.DoesNotExist: + pass + + if not re.match("^\w+$", self.cleaned_data['username']): + raise forms.ValidationError('Username contains illegal characters') + + if 'password' in self.cleaned_data and 'password_again' in self.cleaned_data: + if self.cleaned_data['password'] != self.cleaned_data['password_again']: + raise forms.ValidationError('Passwords do not match') + + if 'email' in self.cleaned_data and 'email_again' in self.cleaned_data: + if self.cleaned_data['email'] != self.cleaned_data['email_again']: + raise forms.ValidationError('Emails do not match') + + return self.cleaned_data diff --git a/authentication/managers.py b/authentication/managers.py index 1ab279b0..f9376a42 100755 --- a/authentication/managers.py +++ b/authentication/managers.py @@ -1,40 +1,22 @@ +from __future__ import unicode_literals from django.contrib.auth.models import User -from models import AuthServicesInfo +from authentication.models import AuthServicesInfo import logging logger = logging.getLogger(__name__) + class AuthServicesInfoManager: def __init__(self): pass @staticmethod - def __get_or_create(user): - if AuthServicesInfo.objects.filter(user=user).exists(): - logger.debug("Returning existing authservicesinfo model for user %s" % user) - return AuthServicesInfo.objects.get(user=user) - else: - # We have to create - logger.info("Creating new authservicesinfo model for user %s" % user) - authserviceinfo = AuthServicesInfo() - authserviceinfo.user = user - authserviceinfo.save() - return authserviceinfo - - @staticmethod - def get_auth_service_info(user): - if User.objects.filter(username=user.username).exists(): - return AuthServicesInfoManager.__get_or_create(user) - logger.error("Failed to get authservicesinfo object for user %s: user does not exist." % user) - return None - - @staticmethod - def update_main_char_Id(char_id, user): + def update_main_char_id(char_id, user): if User.objects.filter(username=user.username).exists(): logger.debug("Updating user %s main character to id %s" % (user, char_id)) - authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo = AuthServicesInfo.objects.get_or_create(user=user)[0] authserviceinfo.main_char_id = char_id authserviceinfo.save(update_fields=['main_char_id']) logger.info("Updated user %s main character to id %s" % (user, char_id)) @@ -42,62 +24,56 @@ class AuthServicesInfoManager: logger.error("Failed to update user %s main character id to %s: user does not exist." % (user, char_id)) @staticmethod - def update_user_forum_info(username, password, user): + def update_user_forum_info(username, user): if User.objects.filter(username=user.username).exists(): logger.debug("Updating user %s forum info: username %s" % (user, username)) - authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo = AuthServicesInfo.objects.get_or_create(user=user)[0] authserviceinfo.forum_username = username - authserviceinfo.forum_password = password - authserviceinfo.save(update_fields=['forum_username', 'forum_password']) + authserviceinfo.save(update_fields=['forum_username']) logger.info("Updated user %s forum info in authservicesinfo model." % user) else: logger.error("Failed to update user %s forum info: user does not exist." % user) @staticmethod - def update_user_jabber_info(username, password, user): + def update_user_jabber_info(username, user): if User.objects.filter(username=user.username).exists(): logger.debug("Updating user %s jabber info: username %s" % (user, username)) - authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo = AuthServicesInfo.objects.get_or_create(user=user)[0] authserviceinfo.jabber_username = username - authserviceinfo.jabber_password = password - authserviceinfo.save(update_fields=['jabber_username', 'jabber_password']) + authserviceinfo.save(update_fields=['jabber_username']) logger.info("Updated user %s jabber info in authservicesinfo model." % user) else: logger.error("Failed to update user %s jabber info: user does not exist." % user) - @staticmethod - def update_user_mumble_info(username, password, user): + def update_user_mumble_info(username, user): if User.objects.filter(username=user.username).exists(): logger.debug("Updating user %s mumble info: username %s" % (user, username)) - authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo = AuthServicesInfo.objects.get_or_create(user=user)[0] authserviceinfo.mumble_username = username - authserviceinfo.mumble_password = password - authserviceinfo.save(update_fields=['mumble_username', 'mumble_password']) + authserviceinfo.save(update_fields=['mumble_username']) logger.info("Updated user %s mumble info in authservicesinfo model." % user) else: logger.error("Failed to update user %s mumble info: user does not exist." % user) @staticmethod - def update_user_ipboard_info(username, password, user): + def update_user_ipboard_info(username, user): if User.objects.filter(username=user.username).exists(): logger.debug("Updating user %s ipboard info: uername %s" % (user, username)) - authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo = AuthServicesInfo.objects.get_or_create(user=user)[0] authserviceinfo.ipboard_username = username - authserviceinfo.ipboard_password = password - authserviceinfo.save(update_fields=['ipboard_username', 'ipboard_password']) + authserviceinfo.save(update_fields=['ipboard_username']) logger.info("Updated user %s ipboard info in authservicesinfo model." % user) else: logger.error("Failed to update user %s ipboard info: user does not exist." % user) @staticmethod - def update_user_xenforo_info(username, password, user): + def update_user_xenforo_info(username, user): if User.objects.filter(username=user.username).exists(): logger.debug("Updating user %s xenforo info: uername %s" % (user, username)) - authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo = AuthServicesInfo.objects.get_or_create(user=user)[0] authserviceinfo.xenforo_username = username - authserviceinfo.xenforo_password = password - authserviceinfo.save(update_fields=['xenforo_username', 'xenforo_password']) + authserviceinfo.save(update_fields=['xenforo_username']) logger.info("Updated user %s xenforo info in authservicesinfo model." % user) else: logger.error("Failed to update user %s xenforo info: user does not exist." % user) @@ -106,7 +82,7 @@ class AuthServicesInfoManager: def update_user_teamspeak3_info(uid, perm_key, user): if User.objects.filter(username=user.username).exists(): logger.debug("Updating user %s teamspeak3 info: uid %s" % (user, uid)) - authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo = AuthServicesInfo.objects.get_or_create(user=user)[0] authserviceinfo.teamspeak3_uid = uid authserviceinfo.teamspeak3_perm_key = perm_key authserviceinfo.save(update_fields=['teamspeak3_uid', 'teamspeak3_perm_key']) @@ -118,7 +94,7 @@ class AuthServicesInfoManager: def update_is_blue(is_blue, user): if User.objects.filter(username=user.username).exists(): logger.debug("Updating user %s blue status: %s" % (user, is_blue)) - authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo = AuthServicesInfo.objects.get_or_create(user=user)[0] authserviceinfo.is_blue = is_blue authserviceinfo.save(update_fields=['is_blue']) logger.info("Updated user %s blue status to %s in authservicesinfo model." % (user, is_blue)) @@ -127,70 +103,54 @@ class AuthServicesInfoManager: def update_user_discord_info(user_id, user): if User.objects.filter(username=user.username).exists(): logger.debug("Updating user %s discord info: user_id %s" % (user, user_id)) - authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo = AuthServicesInfo.objects.get_or_create(user=user)[0] authserviceinfo.discord_uid = user_id authserviceinfo.save(update_fields=['discord_uid']) logger.info("Updated user %s discord info in authservicesinfo model." % user) else: logger.error("Failed to update user %s discord info: user does not exist." % user) - + @staticmethod - def update_user_discourse_info(username, password, user): + def update_user_discourse_info(username, user): if User.objects.filter(username=user.username).exists(): logger.debug("Updating user %s discourse info: username %s" % (user, username)) - authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo = AuthServicesInfo.objects.get_or_create(user=user)[0] authserviceinfo.discourse_username = username - authserviceinfo.discourse_password = password - authserviceinfo.save(update_fields=['discourse_username', 'discourse_password']) + authserviceinfo.save(update_fields=['discourse_username']) logger.info("Updated user %s discourse info in authservicesinfo model." % user) else: logger.error("Failed to update user %s discourse info: user does not exist." % user) @staticmethod - def update_user_ips4_info(username, password, id, user): + def update_user_ips4_info(username, id, user): if User.objects.filter(username=user.username).exists(): logger.debug("Updating user %s IPS4 info: username %s" % (user, username)) - authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo = AuthServicesInfo.objects.get_or_create(user=user)[0] authserviceinfo.ips4_username = username - authserviceinfo.ips4_password = password authserviceinfo.ips4_id = id - authserviceinfo.save(update_fields=['ips4_username', 'ips4_password', 'ips4_id']) + authserviceinfo.save(update_fields=['ips4_username', 'ips4_id']) logger.info("Updated user %s IPS4 info in authservicesinfo model." % user) else: logger.error("Failed to update user %s IPS4 info: user does not exist." % user) @staticmethod - def update_user_smf_info(username, password, user): + def update_user_smf_info(username, user): if User.objects.filter(username=user.username).exists(): logger.debug("Updating user %s forum info: username %s" % (user, username)) - authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo = AuthServicesInfo.objects.get_or_create(user=user)[0] authserviceinfo.smf_username = username - authserviceinfo.smf_password = password - authserviceinfo.save(update_fields=['smf_username', 'smf_password']) + authserviceinfo.save(update_fields=['smf_username']) logger.info("Updated user %s smf info in authservicesinfo model." % user) else: logger.error("Failed to update user %s smf info: user does not exist." % user) @staticmethod - def update_user_market_info(username, password, user): + def update_user_market_info(username, user): if User.objects.filter(username=user.username).exists(): logger.debug("Updating user %s market info: username %s" % (user, username)) - authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo = AuthServicesInfo.objects.get_or_create(user=user)[0] authserviceinfo.market_username = username - authserviceinfo.market_password = password - authserviceinfo.save(update_fields=['market_username', 'market_password']) + authserviceinfo.save(update_fields=['market_username']) logger.info("Updated user %s market info in authservicesinfo model." % user) else: logger.error("Failed to update user %s market info: user does not exist." % user) - - @staticmethod - def update_user_pathfinder_info(username, password, user): - if User.objects.filter(username=user.username).exists(): - logger.debug("Updating user %s market info: username %s" % (user, username)) - authserviceinfo = AuthServicesInfoManager.__get_or_create(user) - authserviceinfo.pathfinder_username = username - authserviceinfo.pathfinder_password = password - authserviceinfo.save(update_fields=['pathfinder_username', 'pathfinder_password']) - logger.info("Updated user %s pathfinder info in authservicesinfo model." % user) - else: - logger.error("Failed to update user %s pathfinder info: user does not exist." % user) diff --git a/authentication/migrations/0001_initial.py b/authentication/migrations/0001_initial.py new file mode 100644 index 00000000..8c5f1f2a --- /dev/null +++ b/authentication/migrations/0001_initial.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-05 21:38 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='AuthServicesInfo', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('ipboard_username', models.CharField(blank=True, default=b'', max_length=254)), + ('ipboard_password', models.CharField(blank=True, default=b'', max_length=254)), + ('xenforo_username', models.CharField(blank=True, default=b'', max_length=254)), + ('xenforo_password', models.CharField(blank=True, default=b'', max_length=254)), + ('forum_username', models.CharField(blank=True, default=b'', max_length=254)), + ('forum_password', models.CharField(blank=True, default=b'', max_length=254)), + ('jabber_username', models.CharField(blank=True, default=b'', max_length=254)), + ('jabber_password', models.CharField(blank=True, default=b'', max_length=254)), + ('mumble_username', models.CharField(blank=True, default=b'', max_length=254)), + ('mumble_password', models.CharField(blank=True, default=b'', max_length=254)), + ('teamspeak3_uid', models.CharField(blank=True, default=b'', max_length=254)), + ('teamspeak3_perm_key', models.CharField(blank=True, default=b'', max_length=254)), + ('discord_uid', models.CharField(blank=True, default=b'', max_length=254)), + ('discourse_username', models.CharField(blank=True, default=b'', max_length=254)), + ('discourse_password', models.CharField(blank=True, default=b'', max_length=254)), + ('ips4_username', models.CharField(blank=True, default=b'', max_length=254)), + ('ips4_password', models.CharField(blank=True, default=b'', max_length=254)), + ('ips4_id', models.CharField(blank=True, default=b'', max_length=254)), + ('smf_username', models.CharField(blank=True, default=b'', max_length=254)), + ('smf_password', models.CharField(blank=True, default=b'', max_length=254)), + ('market_username', models.CharField(blank=True, default=b'', max_length=254)), + ('market_password', models.CharField(blank=True, default=b'', max_length=254)), + ('pathfinder_username', models.CharField(blank=True, default=b'', max_length=254)), + ('pathfinder_password', models.CharField(blank=True, default=b'', max_length=254)), + ('main_char_id', models.CharField(blank=True, default=b'', max_length=64)), + ('is_blue', models.BooleanField(default=False)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/authentication/migrations/0002_auto_20160907_1914.py b/authentication/migrations/0002_auto_20160907_1914.py new file mode 100644 index 00000000..c6614a92 --- /dev/null +++ b/authentication/migrations/0002_auto_20160907_1914.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-07 19:14 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='authservicesinfo', + name='pathfinder_password', + ), + migrations.RemoveField( + model_name='authservicesinfo', + name='pathfinder_username', + ), + ] diff --git a/authentication/migrations/0003_authservicesinfo_state.py b/authentication/migrations/0003_authservicesinfo_state.py new file mode 100644 index 00000000..cac17cd3 --- /dev/null +++ b/authentication/migrations/0003_authservicesinfo_state.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-09 20:29 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0002_auto_20160907_1914'), + ] + + operations = [ + migrations.AddField( + model_name='authservicesinfo', + name='state', + field=models.CharField(blank=True, choices=[(None, b'None'), (b'Blue', b'Blue'), (b'Member', b'Member')], default=None, max_length=10, null=True), + ), + ] diff --git a/authentication/migrations/0004_create_permissions.py b/authentication/migrations/0004_create_permissions.py new file mode 100644 index 00000000..3dc4acfb --- /dev/null +++ b/authentication/migrations/0004_create_permissions.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-09 23:19 +from __future__ import unicode_literals + +from django.db import migrations + +def create_permissions(apps, schema_editor): + User = apps.get_model('auth', 'User') + ContentType = apps.get_model('contenttypes', 'ContentType') + Permission = apps.get_model('auth', 'Permission') + ct = ContentType.objects.get_for_model(User) + Permission.objects.get_or_create(codename="member", content_type=ct, name="member") + Permission.objects.get_or_create(codename="group_management", content_type=ct, name="group_management") + Permission.objects.get_or_create(codename="jabber_broadcast", content_type=ct, name="jabber_broadcast") + Permission.objects.get_or_create(codename="jabber_broadcast_all", content_type=ct, name="jabber_broadcast_all") + Permission.objects.get_or_create(codename="fleetactivitytracking", content_type=ct, name="fleetactivitytracking") + Permission.objects.get_or_create(codename="fleetactivitytracking_statistics", content_type=ct, name="fleetactivitytracking_statistics") + Permission.objects.get_or_create(codename="human_resources", content_type=ct, name="human_resources") + Permission.objects.get_or_create(codename="blue_member", content_type=ct, name="blue_member") + Permission.objects.get_or_create(codename="alliance_apis", content_type=ct, name="alliance_apis") + Permission.objects.get_or_create(codename="corp_apis", content_type=ct, name="corp_apis") + Permission.objects.get_or_create(codename="timer_management", content_type=ct, name="timer_management") + Permission.objects.get_or_create(codename="timer_view", content_type=ct, name="timer_view") + Permission.objects.get_or_create(codename="srp_management", content_type=ct, name="srp_management") + Permission.objects.get_or_create(codename="signature_management", content_type=ct, name="signature_management") + Permission.objects.get_or_create(codename="signature_view", content_type=ct, name="signature_view") + Permission.objects.get_or_create(codename="optimer_management", content_type=ct, name="optimer_management") + Permission.objects.get_or_create(codename="optimer_view", content_type=ct, name="optimer_view") + Permission.objects.get_or_create(codename="logging_notifications", content_type=ct, name="logging_notifications") + +def reverse(apps, schema_editor): + #too lazy + pass + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0003_authservicesinfo_state'), + ] + + operations = [ + migrations.RunPython(create_permissions, reverse) + ] diff --git a/authentication/migrations/0005_delete_perms.py b/authentication/migrations/0005_delete_perms.py new file mode 100644 index 00000000..e10f4253 --- /dev/null +++ b/authentication/migrations/0005_delete_perms.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-09 23:11 +from __future__ import unicode_literals + +from django.db import migrations + +def delete_permissions(apps, schema_editor): + User = apps.get_model('auth', 'User') + ContentType = apps.get_model('contenttypes', 'ContentType') + Permission = apps.get_model('auth', 'Permission') + ct = ContentType.objects.get_for_model(User) + Permission.objects.filter(content_type=ct).filter(codename__in=['member', 'blue_member', 'signature_management', 'signature_view']).delete() + +def create_permissions(apps, schema_editor): + User = apps.get_model('auth', 'User') + ContentType = apps.get_model('contenttypes', 'ContentType') + Permission = apps.get_model('auth', 'Permission') + ct = ContentType.objects.get_for_model(User) + Permission.objects.get_or_create(codename="member", content_type=ct, name="member") + Permission.objects.get_or_create(codename="blue_member", content_type=ct, name="blue_member") + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0004_create_permissions'), + ] + + operations = [ + migrations.RunPython(delete_permissions, create_permissions), + ] diff --git a/authentication/migrations/0006_auto_20160910_0542.py b/authentication/migrations/0006_auto_20160910_0542.py new file mode 100644 index 00000000..d7a24797 --- /dev/null +++ b/authentication/migrations/0006_auto_20160910_0542.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-10 05:42 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0005_delete_perms'), + ] + + operations = [ + migrations.RemoveField( + model_name='authservicesinfo', + name='discourse_password', + ), + migrations.RemoveField( + model_name='authservicesinfo', + name='forum_password', + ), + migrations.RemoveField( + model_name='authservicesinfo', + name='ipboard_password', + ), + migrations.RemoveField( + model_name='authservicesinfo', + name='ips4_password', + ), + migrations.RemoveField( + model_name='authservicesinfo', + name='jabber_password', + ), + migrations.RemoveField( + model_name='authservicesinfo', + name='market_password', + ), + migrations.RemoveField( + model_name='authservicesinfo', + name='mumble_password', + ), + migrations.RemoveField( + model_name='authservicesinfo', + name='smf_password', + ), + migrations.RemoveField( + model_name='authservicesinfo', + name='xenforo_password', + ), + ] diff --git a/authentication/migrations/0007_remove_authservicesinfo_is_blue.py b/authentication/migrations/0007_remove_authservicesinfo_is_blue.py new file mode 100644 index 00000000..037c2092 --- /dev/null +++ b/authentication/migrations/0007_remove_authservicesinfo_is_blue.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-10 21:50 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0006_auto_20160910_0542'), + ] + + operations = [ + migrations.RemoveField( + model_name='authservicesinfo', + name='is_blue', + ), + ] diff --git a/authentication/migrations/0008_set_state.py b/authentication/migrations/0008_set_state.py new file mode 100644 index 00000000..91eccaf7 --- /dev/null +++ b/authentication/migrations/0008_set_state.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-12 13:04 +from __future__ import unicode_literals + +from django.db import migrations + +from authentication.states import MEMBER_STATE, BLUE_STATE, NONE_STATE +from django.conf import settings + +def determine_membership_by_character(char, apps): + if settings.IS_CORP: + if int(char.corporation_id) == int(settings.CORP_ID): + return MEMBER_STATE + else: + if int(char.alliance_id) == int(settings.ALLIANCE_ID): + return MEMBER_STATE + EveCorporationInfo = apps.get_model('eveonline', 'EveCorporationInfo') + if EveCorporationInfo.objects.filter(corporation_id=char.corporation_id).exists() is False: + return NONE_STATE + else: + corp = EveCorporationInfo.objects.get(corporation_id=char.corporation_id) + if corp.is_blue: + return BLUE_STATE + else: + return NONE_STATE + +def determine_membership_by_user(user, apps): + AuthServicesInfo = apps.get_model('authentication', 'AuthServicesInfo') + auth, c = AuthServicesInfo.objects.get_or_create(user=user) + if auth.main_char_id: + EveCharacter = apps.get_model('eveonline', 'EveCharacter') + if EveCharacter.objects.filter(character_id=auth.main_char_id).exists(): + char = EveCharacter.objects.get(character_id=auth.main_char_id) + return determine_membership_by_character(char, apps) + else: + return NONE_STATE + else: + return NONE_STATE + +def set_state(user, apps): + if user.is_active: + state = determine_membership_by_user(user, apps) + else: + state = NONE_STATE + AuthServicesInfo = apps.get_model('authentication', 'AuthServicesInfo') + auth = AuthServicesInfo.objects.get_or_create(user=user)[0] + if auth.state != state: + auth.state = state + auth.save() + +def set_initial_state(apps, schema_editor): + User = apps.get_model('auth', 'User') + for u in User.objects.all(): + set_state(u, apps) + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0007_remove_authservicesinfo_is_blue'), + ('eveonline', '0001_initial'), + ('auth', '0001_initial'), + ] + + operations = [ + migrations.RunPython(set_initial_state, migrations.RunPython.noop) + ] diff --git a/portal/__init__.py b/authentication/migrations/__init__.py similarity index 100% rename from portal/__init__.py rename to authentication/migrations/__init__.py diff --git a/authentication/models.py b/authentication/models.py index aaed9119..b9a69bde 100755 --- a/authentication/models.py +++ b/authentication/models.py @@ -1,35 +1,34 @@ +from __future__ import unicode_literals +from django.utils.encoding import python_2_unicode_compatible from django.db import models from django.contrib.auth.models import User +from authentication.states import MEMBER_STATE, BLUE_STATE, NONE_STATE +@python_2_unicode_compatible class AuthServicesInfo(models.Model): + STATE_CHOICES = ( + (NONE_STATE, 'None'), + (BLUE_STATE, 'Blue'), + (MEMBER_STATE, 'Member'), + ) + ipboard_username = models.CharField(max_length=254, blank=True, default="") - ipboard_password = models.CharField(max_length=254, blank=True, default="") xenforo_username = models.CharField(max_length=254, blank=True, default="") - xenforo_password = models.CharField(max_length=254, blank=True, default="") forum_username = models.CharField(max_length=254, blank=True, default="") - forum_password = models.CharField(max_length=254, blank=True, default="") jabber_username = models.CharField(max_length=254, blank=True, default="") - jabber_password = models.CharField(max_length=254, blank=True, default="") mumble_username = models.CharField(max_length=254, blank=True, default="") - mumble_password = models.CharField(max_length=254, blank=True, default="") teamspeak3_uid = models.CharField(max_length=254, blank=True, default="") teamspeak3_perm_key = models.CharField(max_length=254, blank=True, default="") discord_uid = models.CharField(max_length=254, blank=True, default="") discourse_username = models.CharField(max_length=254, blank=True, default="") - discourse_password = models.CharField(max_length=254, blank=True, default="") ips4_username = models.CharField(max_length=254, blank=True, default="") - ips4_password = models.CharField(max_length=254, blank=True, default="") ips4_id = models.CharField(max_length=254, blank=True, default="") smf_username = models.CharField(max_length=254, blank=True, default="") - smf_password = models.CharField(max_length=254, blank=True, default="") market_username = models.CharField(max_length=254, blank=True, default="") - market_password = models.CharField(max_length=254, blank=True, default="") - pathfinder_username = models.CharField(max_length=254, blank=True, default="") - pathfinder_password = models.CharField(max_length=254, blank=True, default="") main_char_id = models.CharField(max_length=64, blank=True, default="") - is_blue = models.BooleanField(default=False) user = models.ForeignKey(User) + state = models.CharField(blank=True, null=True, choices=STATE_CHOICES, default=NONE_STATE, max_length=10) def __str__(self): return self.user.username + ' - AuthInfo' diff --git a/authentication/signals.py b/authentication/signals.py new file mode 100644 index 00000000..929eea6f --- /dev/null +++ b/authentication/signals.py @@ -0,0 +1,25 @@ +from __future__ import unicode_literals +from django.db.models.signals import pre_save +from django.dispatch import receiver +from authentication.models import AuthServicesInfo +from authentication.states import MEMBER_STATE, BLUE_STATE +from authentication.tasks import make_member, make_blue, disable_member +from services.tasks import validate_services +import logging + +logger = logging.getLogger(__name__) + + +@receiver(pre_save, sender=AuthServicesInfo) +def pre_save_auth_state(sender, instance, *args, **kwargs): + if instance.pk: + old_instance = AuthServicesInfo.objects.get(pk=instance.pk) + if old_instance.state != instance.state: + logger.debug('Detected state change for %s' % instance.user) + if instance.state == MEMBER_STATE: + make_member(instance) + elif instance.state == BLUE_STATE: + make_blue(instance) + else: + disable_member(instance.user) + validate_services(instance.user, instance.state) diff --git a/authentication/states.py b/authentication/states.py new file mode 100644 index 00000000..48c76952 --- /dev/null +++ b/authentication/states.py @@ -0,0 +1,4 @@ +from __future__ import unicode_literals +MEMBER_STATE = 'Member' +BLUE_STATE = 'Blue' +NONE_STATE = None diff --git a/authentication/tasks.py b/authentication/tasks.py new file mode 100644 index 00000000..4e7ff355 --- /dev/null +++ b/authentication/tasks.py @@ -0,0 +1,168 @@ +from __future__ import unicode_literals +from services.tasks import validate_services +from django.contrib.auth.models import Group +from authentication.models import AuthServicesInfo +from authentication.states import MEMBER_STATE, BLUE_STATE, NONE_STATE +from eveonline.models import EveCharacter, EveCorporationInfo +from notifications import notify +from django.conf import settings +import logging + +logger = logging.getLogger(__name__) + + +def generate_corp_group_name(corpname): + return 'Corp_' + corpname.replace(' ', '_') + + +def generate_alliance_group_name(alliancename): + return 'Alliance_' + alliancename.replace(' ', '_') + + +def disable_member(user): + logger.debug("Disabling member %s" % user) + if user.user_permissions.all().exists(): + logger.info("Clearning user %s permission to deactivate user." % user) + user.user_permissions.clear() + if user.groups.all().exists(): + logger.info("Clearing user %s groups to deactivate user." % user) + user.groups.clear() + validate_services(user, None) + + +def make_member(auth): + logger.debug("Ensuring user %s has member permissions and groups." % auth.user) + # ensure member is not blue right now + blue_group, c = Group.objects.get_or_create(name=settings.DEFAULT_BLUE_GROUP) + if blue_group in auth.user.groups.all(): + logger.info("Removing user %s blue group" % auth.user) + auth.user.groups.remove(blue_group) + # make member + member_group, c = Group.objects.get_or_create(name=settings.DEFAULT_AUTH_GROUP) + if member_group not in auth.user.groups.all(): + logger.info("Adding user %s to member group" % auth.user) + auth.user.groups.add(member_group) + assign_corp_group(auth) + assign_alliance_group(auth) + + +def make_blue(auth): + logger.debug("Ensuring user %s has blue permissions and groups." % auth.user) + # ensure user is not a member + member_group, c = Group.objects.get_or_create(name=settings.DEFAULT_AUTH_GROUP) + if member_group in auth.user.groups.all(): + logger.info("Removing user %s member group" % auth.user) + auth.user.groups.remove(member_group) + # make blue + blue_group, c = Group.objects.get_or_create(name=settings.DEFAULT_BLUE_GROUP) + if blue_group not in auth.user.groups.all(): + logger.info("Adding user %s to blue group" % auth.user) + auth.user.groups.add(blue_group) + assign_corp_group(auth) + assign_alliance_group(auth) + + +def determine_membership_by_character(char): + if settings.IS_CORP: + if int(char.corporation_id) == int(settings.CORP_ID): + logger.debug("Character %s in owning corp id %s" % (char, char.corporation_id)) + return MEMBER_STATE + else: + if int(char.alliance_id) == int(settings.ALLIANCE_ID): + logger.debug("Character %s in owning alliance id %s" % (char, char.alliance_id)) + return MEMBER_STATE + if EveCorporationInfo.objects.filter(corporation_id=char.corporation_id).exists() is False: + logger.debug("No corp model for character %s corp id %s. Unable to check standings. Non-member." % ( + char, char.corporation_id)) + return NONE_STATE + else: + corp = EveCorporationInfo.objects.get(corporation_id=char.corporation_id) + if corp.is_blue: + logger.debug("Character %s member of blue corp %s" % (char, corp)) + return BLUE_STATE + else: + logger.debug("Character %s member of non-blue corp %s. Non-member." % (char, corp)) + return NONE_STATE + + +def determine_membership_by_user(user): + logger.debug("Determining membership of user %s" % user) + auth, c = AuthServicesInfo.objects.get_or_create(user=user) + if auth.main_char_id: + if EveCharacter.objects.filter(character_id=auth.main_char_id).exists(): + char = EveCharacter.objects.get(character_id=auth.main_char_id) + return determine_membership_by_character(char) + else: + logger.debug("Character model matching user %s main character id %s does not exist. Non-member." % ( + user, auth.main_char_id)) + return NONE_STATE + else: + logger.debug("User %s has no main character set. Non-member." % user) + return NONE_STATE + + +def set_state(user): + if user.is_active: + state = determine_membership_by_user(user) + else: + state = NONE_STATE + logger.debug("Assigning user %s to state %s" % (user, state)) + auth = AuthServicesInfo.objects.get_or_create(user=user)[0] + if auth.state != state: + auth.state = state + auth.save() + notify(user, "Membership State Change", message="You membership state has been changed to %s" % state) + + +def assign_corp_group(auth): + corp_group = None + if auth.main_char_id: + if EveCharacter.objects.filter(character_id=auth.main_char_id).exists(): + char = EveCharacter.objects.get(character_id=auth.main_char_id) + corpname = generate_corp_group_name(char.corporation_name) + if auth.state == BLUE_STATE and settings.BLUE_CORP_GROUPS: + logger.debug("Validating blue user %s has corp group assigned." % auth.user) + corp_group, c = Group.objects.get_or_create(name=corpname) + elif auth.state == MEMBER_STATE and settings.MEMBER_CORP_GROUPS: + logger.debug("Validating member %s has corp group assigned." % auth.user) + corp_group, c = Group.objects.get_or_create(name=corpname) + else: + logger.debug("Ensuring %s has no corp groups assigned." % auth.user) + if corp_group: + if corp_group not in auth.user.groups.all(): + logger.info("Adding user %s to corp group %s" % (auth.user, corp_group)) + auth.user.groups.add(corp_group) + for g in auth.user.groups.all(): + if str.startswith(str(g.name), "Corp_"): + if g != corp_group: + logger.info("Removing user %s from old corpgroup %s" % (auth.user, g)) + auth.user.groups.remove(g) + + +def assign_alliance_group(auth): + alliance_group = None + if auth.main_char_id: + if EveCharacter.objects.filter(character_id=auth.main_char_id).exists(): + char = EveCharacter.objects.get(character_id=auth.main_char_id) + if char.alliance_name: + alliancename = generate_alliance_group_name(char.alliance_name) + if auth.state == BLUE_STATE and settings.BLUE_ALLIANCE_GROUPS: + logger.debug("Validating blue user %s has alliance group assigned." % auth.user) + alliance_group, c = Group.objects.get_or_create(name=alliancename) + elif auth.state == MEMBER_STATE and settings.MEMBER_ALLIANCE_GROUPS: + logger.debug("Validating member %s has alliance group assigned." % auth.user) + alliance_group, c = Group.objects.get_or_create(name=alliancename) + else: + logger.debug("Ensuring %s has no alliance groups assigned." % auth.user) + else: + logger.debug("User %s main character %s not in an alliance. Ensuring no alliance group assigned." % ( + auth.user, char)) + if alliance_group: + if alliance_group not in auth.user.groups.all(): + logger.info("Adding user %s to alliance group %s" % (auth.user, alliance_group)) + auth.user.groups.add(alliance_group) + for g in auth.user.groups.all(): + if str.startswith(str(g.name), "Alliance_"): + if g != alliance_group: + logger.info("Removing user %s from old alliance group %s" % (auth.user, g)) + auth.user.groups.remove(g) diff --git a/authentication/views.py b/authentication/views.py index 0d250b8e..6093c119 100644 --- a/authentication/views.py +++ b/authentication/views.py @@ -1,17 +1,21 @@ +from __future__ import unicode_literals from django.contrib.auth import login from django.contrib.auth import logout from django.contrib.auth import authenticate -from django.http import HttpResponseRedirect -from django.shortcuts import render_to_response -from django.template import RequestContext -from django.utils import translation - -from forms import LoginForm - +from django.shortcuts import render, redirect +from django.contrib.auth.decorators import login_required +from eveonline.managers import EveManager +from eveonline.models import EveCharacter +from authentication.models import AuthServicesInfo +from authentication.forms import LoginForm, RegistrationForm +from django.contrib.auth.models import User +from django.contrib import messages +from eve_sso.decorators import token_required import logging logger = logging.getLogger(__name__) + def login_user(request): logger.debug("login_user called by user %s" % request.user) if request.method == 'POST': @@ -24,24 +28,89 @@ def login_user(request): if user.is_active: logger.info("Successful login attempt from user %s" % user) login(request, user) - return HttpResponseRedirect("/dashboard/") + return redirect("auth_dashboard") else: logger.info("Login attempt failed for user %s: user marked inactive." % user) + messages.warning(request, 'Your account has been disabled.') else: logger.info("Failed login attempt: provided username %s" % form.cleaned_data['username']) - - return render_to_response('public/login.html', {'form': form, 'error': True}, - context_instance=RequestContext(request)) + messages.error(request, 'Username/password invalid.') + return render(request, 'public/login.html', context={'form': form}) else: logger.debug("Providing new login form.") form = LoginForm() - return render_to_response('public/login.html', {'form': form}, context_instance=RequestContext(request)) + return render(request, 'public/login.html', context={'form': form}) def logout_user(request): logger.debug("logout_user called by user %s" % request.user) - logoutUser = request.user + temp_user = request.user logout(request) - logger.info("Successful logout for user %s" % logoutUser) - return HttpResponseRedirect("/") \ No newline at end of file + logger.info("Successful logout for user %s" % temp_user) + return redirect("auth_index") + + +def register_user_view(request): + logger.debug("register_user_view called by user %s" % request.user) + if request.method == 'POST': + form = RegistrationForm(request.POST) + logger.debug("Request type POST contains form valid: %s" % form.is_valid()) + if form.is_valid(): + + if not User.objects.filter(username=form.cleaned_data['username']).exists(): + user = User.objects.create_user(form.cleaned_data['username'], + form.cleaned_data['email'], form.cleaned_data['password']) + + user.save() + logger.info("Created new user %s" % user) + messages.warning(request, 'Add an API key to set up your account.') + return redirect("auth_dashboard") + + else: + logger.error("Unable to register new user: username %s already exists." % form.cleaned_data['username']) + return render(request, 'public/register.html', context={'form': form, 'error': True}) + else: + logger.debug("Registration form invalid. Returning for user %s to make corrections." % request.user) + + else: + logger.debug("Returning blank registration form.") + form = RegistrationForm() + + return render(request, 'public/register.html', context={'form': form}) + + +def index_view(request): + logger.debug("index_view called by user %s" % request.user) + return render(request, 'public/index.html') + + +@login_required +def dashboard_view(request): + logger.debug("dashboard_view called by user %s" % request.user) + render_items = {'characters': EveManager.get_characters_by_owner_id(request.user.id), + 'authinfo': AuthServicesInfo.objects.get_or_create(user=request.user)[0]} + return render(request, 'registered/dashboard.html', context=render_items) + + +@login_required +def help_view(request): + logger.debug("help_view called by user %s" % request.user) + return render(request, 'registered/help.html') + +@token_required(new=True) +def sso_login(request, tokens=[]): + token = tokens[0] + try: + char = EveCharacter.objects.get(character_id=token.character_id) + if char.user: + if char.user.is_active: + login(request, char.user) + return redirect(dashboard_view) + else: + messages.error(request, 'Your account has been disabled.') + else: + messages.warning(request, 'Authenticated character has no owning account. Please log in with username and password.') + except EveCharacter.DoesNotExist: + messages.error(request, 'No account exists with the authenticated character. Please create an account first.') + return redirect(login_user) diff --git a/celerytask/__init__.py b/celerytask/__init__.py deleted file mode 100644 index b31856c4..00000000 --- a/celerytask/__init__.py +++ /dev/null @@ -1 +0,0 @@ -import signals diff --git a/celerytask/admin.py b/celerytask/admin.py deleted file mode 100644 index c608d24f..00000000 --- a/celerytask/admin.py +++ /dev/null @@ -1,7 +0,0 @@ -from django.contrib import admin - -from models import SyncGroupCache - - -# Register your models here. -admin.site.register(SyncGroupCache) \ No newline at end of file diff --git a/celerytask/models.py b/celerytask/models.py deleted file mode 100755 index 3d14398a..00000000 --- a/celerytask/models.py +++ /dev/null @@ -1,12 +0,0 @@ -from django.db import models -from django.contrib.auth.models import User - - -class SyncGroupCache(models.Model): - groupname = models.CharField(max_length=254) - servicename = models.CharField(max_length=254, default="") - - user = models.ForeignKey(User) - - def __str__(self): - return self.user.username + ' - ' + self.groupname + ' - ' + self.servicename + ' - SyncGroupCache' diff --git a/celerytask/tasks.py b/celerytask/tasks.py deleted file mode 100644 index 40725a30..00000000 --- a/celerytask/tasks.py +++ /dev/null @@ -1,785 +0,0 @@ -from django.conf import settings -from celery.task import periodic_task -from django.contrib.auth.models import User -from django.contrib.auth.models import Group -from notifications import notify -from celery import task -from celery.task.schedules import crontab -from services.managers.openfire_manager import OpenfireManager -from services.managers.mumble_manager import MumbleManager -from services.managers.phpbb3_manager import Phpbb3Manager -from services.managers.ipboard_manager import IPBoardManager -from services.managers.xenforo_manager import XenForoManager -from services.managers.teamspeak3_manager import Teamspeak3Manager -from services.managers.discord_manager import DiscordOAuthManager -from services.managers.discourse_manager import DiscourseManager -from services.managers.smf_manager import smfManager -from services.models import AuthTS -from services.models import TSgroup -from authentication.models import AuthServicesInfo -from eveonline.managers import EveManager -from services.managers.eve_api_manager import EveApiManager -from util.common_task import deactivate_services -from util import add_member_permission -from util import remove_member_permission -from util import check_if_user_has_permission -from util.common_task import add_user_to_group -from util.common_task import remove_user_from_group -from util.common_task import generate_corp_group_name -from util.common_task import generate_alliance_group_name -from eveonline.models import EveCharacter -from eveonline.models import EveCorporationInfo -from eveonline.models import EveAllianceInfo -from authentication.managers import AuthServicesInfoManager -from services.models import DiscordAuthToken - -import evelink -import time -import logging - -logger = logging.getLogger(__name__) - -def disable_member(user): - change = False - logger.debug("Disabling member %s" % user) - if user.user_permissions.all().exists(): - logger.info("Clearning user %s permission to deactivate user." % user) - user.user_permissions.clear() - change = True - if user.groups.all().exists(): - logger.info("Clearing user %s groups to deactivate user." % user) - user.groups.clear() - change = True - deactivate_services(user) - return change - -def is_teamspeak3_active(): - return settings.ENABLE_AUTH_TEAMSPEAK3 or settings.ENABLE_BLUE_TEAMSPEAK3 - -@task -def update_jabber_groups(pk): - user = User.objects.get(pk=pk) - logger.debug("Updating jabber groups for user %s" % user) - authserviceinfo = AuthServicesInfo.objects.get(user=user) - groups = [] - for group in user.groups.all(): - groups.append(str(group.name)) - if len(groups) == 0: - groups.append('empty') - logger.debug("Updating user %s jabber groups to %s" % (user, groups)) - try: - OpenfireManager.update_user_groups(authserviceinfo.jabber_username, authserviceinfo.jabber_password, groups) - except: - logger.exception("Jabber group sync failed for %s, retrying in 10 mins" % user) - raise self.retry(countdown = 60 * 10) - logger.debug("Updated user %s jabber groups." % user) - -@task -def update_all_jabber_groups(): - logger.debug("Updating ALL jabber groups") - for user in AuthServicesInfo.objects.exclude(jabber_username__exact=''): - update_jabber_groups.delay(user.user_id) - -@task -def update_mumble_groups(pk): - user = User.objects.get(pk=pk) - logger.debug("Updating mumble groups for user %s" % user) - authserviceinfo = AuthServicesInfo.objects.get(user=user) - groups = [] - for group in user.groups.all(): - groups.append(str(group.name)) - if len(groups) == 0: - groups.append('empty') - logger.debug("Updating user %s mumble groups to %s" % (user, groups)) - try: - MumbleManager.update_groups(authserviceinfo.mumble_username, groups) - except: - logger.exception("Mumble group sync failed for %s, retrying in 10 mins" % user) - raise self.retry(countdown = 60 * 10) - logger.debug("Updated user %s mumble groups." % user) - -@task -def update_all_mumble_groups(): - logger.debug("Updating ALL mumble groups") - for user in AuthServicesInfo.objects.exclude(mumble_username__exact=''): - update_mumble_groups.delay(user.user_id) - -@task -def update_forum_groups(pk): - user = User.objects.get(pk=pk) - logger.debug("Updating forum groups for user %s" % user) - authserviceinfo = AuthServicesInfo.objects.get(user=user) - groups = [] - for group in user.groups.all(): - groups.append(str(group.name)) - if len(groups) == 0: - groups.append('empty') - logger.debug("Updating user %s forum groups to %s" % (user, groups)) - try: - Phpbb3Manager.update_groups(authserviceinfo.forum_username, groups) - except: - logger.exception("Phpbb group sync failed for %s, retrying in 10 mins" % user) - raise self.retry(countdown = 60 * 10) - logger.debug("Updated user %s forum groups." % user) - -@task -def update_all_forum_groups(): - logger.debug("Updating ALL forum groups") - for user in AuthServicesInfo.objects.exclude(forum_username__exact=''): - update_forum_groups.delay(user.user_id) - -@task -def update_smf_groups(pk): - user = User.objects.get(pk=pk) - logger.debug("Updating smf groups for user %s" % user) - authserviceinfo = AuthServicesInfo.objects.get(user=user) - groups = [] - for group in user.groups.all(): - groups.append(str(group.name)) - if len(groups) == 0: - groups.append('empty') - logger.debug("Updating user %s smf groups to %s" % (user, groups)) - try: - smfManager.update_groups(authserviceinfo.smf_username, groups) - except: - logger.exception("smf group sync failed for %s, retrying in 10 mins" % user) - raise self.retry(countdown = 60 * 10) - logger.debug("Updated user %s smf groups." % user) - -@task -def update_all_smf_groups(): - logger.debug("Updating ALL smf groups") - for user in AuthServicesInfo.objects.exclude(smf_username__exact=''): - update_smf_groups.delay(user.user_id) - -@task -def update_ipboard_groups(pk): - user = User.objects.get(pk=pk) - logger.debug("Updating user %s ipboard groups." % user) - authserviceinfo = AuthServicesInfo.objects.get(user=user) - groups = [] - for group in user.groups.all(): - groups.append(str(group.name)) - if len(groups) == 0: - groups.append('empty') - logger.debug("Updating user %s ipboard groups to %s" % (user, groups)) - try: - IPBoardManager.update_groups(authserviceinfo.ipboard_username, groups) - except: - logger.exception("IPBoard group sync failed for %s, retrying in 10 mins" % user) - raise self.retry(countdown = 60 * 10) - logger.debug("Updated user %s ipboard groups." % user) - -@task -def update_all_ipboard_groups(): - logger.debug("Updating ALL ipboard groups") - for user in AuthServicesInfo.objects.exclude(ipboard_username__exact=''): - update_ipboard_groups.delay(user.user_id) - -@task -def update_teamspeak3_groups(pk): - user = User.objects.get(pk=pk) - logger.debug("Updating user %s teamspeak3 groups" % user) - usergroups = user.groups.all() - authserviceinfo = AuthServicesInfo.objects.get(user=user) - groups = {} - for usergroup in usergroups: - filtered_groups = AuthTS.objects.filter(auth_group=usergroup) - if filtered_groups: - for filtered_group in filtered_groups: - for ts_group in filtered_group.ts_group.all(): - groups[ts_group.ts_group_name] = ts_group.ts_group_id - logger.debug("Updating user %s teamspeak3 groups to %s" % (user, groups)) - Teamspeak3Manager.update_groups(authserviceinfo.teamspeak3_uid, groups) - logger.debug("Updated user %s teamspeak3 groups." % user) - -@task -def update_all_teamspeak3_groups(): - logger.debug("Updating ALL teamspeak3 groups") - for user in AuthServicesInfo.objects.exclude(teamspeak3_uid__exact=''): - update_teamspeak3_groups.delay(user.user_id) - -@task -def update_discord_groups(pk): - user = User.objects.get(pk=pk) - logger.debug("Updating discord groups for user %s" % user) - authserviceinfo = AuthServicesInfo.objects.get(user=user) - groups = [] - for group in user.groups.all(): - groups.append(str(group.name)) - if len(groups) == 0: - logger.debug("No syncgroups found for user. Adding empty group.") - groups.append('empty') - logger.debug("Updating user %s discord groups to %s" % (user, groups)) - try: - DiscordOAuthManager.update_groups(authserviceinfo.discord_uid, groups) - except: - logger.exception("Discord group sync failed for %s, retrying in 10 mins" % user) - raise self.retry(countdown = 60 * 10) - logger.debug("Updated user %s discord groups." % user) - -@task -def update_all_discord_groups(): - logger.debug("Updating ALL discord groups") - for user in AuthServicesInfo.objects.exclude(discord_uid__exact=''): - update_discord_groups.delay(user.user_id) - -@task -def update_discord_nickname(pk): - user = User.objects.get(pk=pk) - logger.debug("Updating discord nickname for user %s" % user) - authserviceinfo = AuthServicesInfo.objects.get(user=user) - character = EveManager.get_character_by_id(authserviceinfo.main_char_id) - logger.debug("Updating user %s discord nickname to %s" % (user, character.character_name)) - try: - DiscordOAuthManager.update_nickname(authserviceinfo.discord_uid, character.character_name) - except: - logger.exception("Discord nickname sync failed for %s, retrying in 10 mins" % user) - raise self.retry(countdown = 60 * 10) - logger.debug("Updated user %s discord nickname." % user) - -@task -def update_all_discord_nicknames(): - logger.debug("Updating ALL discord nicknames") - for user in AuthServicesInfo.objects.exclude(discord_uid__exact=''): - update_discord_nickname(user.user_id) - -@task -def update_discourse_groups(pk): - user = User.objects.get(pk=pk) - logger.debug("Updating discourse groups for user %s" % user) - authserviceinfo = AuthServicesInfo.objects.get(user=user) - groups = [] - for group in user.groups.all(): - groups.append(str(group.name)) - if len(groups) == 0: - logger.debug("No syncgroups found for user. Adding empty group.") - groups.append('empty') - logger.debug("Updating user %s discourse groups to %s" % (user, groups)) - try: - DiscourseManager.update_groups(authserviceinfo.discourse_username, groups) - except: - logger.warn("Discourse group sync failed for %s, retrying in 10 mins" % user, exc_info=True) - raise self.retry(countdown = 60 * 10) - logger.debug("Updated user %s discourse groups." % user) - -@task -def update_all_discourse_groups(): - logger.debug("Updating ALL discourse groups") - for user in AuthServicesInfo.objects.exclude(discourse_username__exact=''): - update_discourse_groups.delay(user.user_id) - - -def assign_corp_group(auth): - corp_group = None - if auth.main_char_id: - if EveCharacter.objects.filter(character_id=auth.main_char_id).exists(): - char = EveCharacter.objects.get(character_id=auth.main_char_id) - corpname = generate_corp_group_name(char.corporation_name) - state = determine_membership_by_character(char) - if state == "BLUE" and settings.BLUE_CORP_GROUPS: - logger.debug("Validating blue user %s has corp group assigned." % auth.user) - corp_group, c = Group.objects.get_or_create(name=corpname) - elif state == "MEMBER" and settings.MEMBER_CORP_GROUPS: - logger.debug("Validating member %s has corp group assigned." % auth.user) - corp_group, c = Group.objects.get_or_create(name=corpname) - else: - logger.debug("Ensuring non-member %s has no corp groups assigned." % auth.user) - if corp_group: - if not corp_group in auth.user.groups.all(): - logger.info("Adding user %s to corp group %s" % (auth.user, corp_group)) - auth.user.groups.add(corp_group) - for g in auth.user.groups.all(): - if str.startswith(str(g.name), "Corp_"): - if g != corp_group: - logger.info("Removing user %s from old corpgroup %s" % (auth.user, g)) - auth.user.groups.remove(g) - -def assign_alliance_group(auth): - alliance_group = None - if auth.main_char_id: - if EveCharacter.objects.filter(character_id=auth.main_char_id).exists(): - char = EveCharacter.objects.get(character_id=auth.main_char_id) - if char.alliance_name: - alliancename = generate_alliance_group_name(char.alliance_name) - state = determine_membership_by_character(char) - if state == "BLUE" and settings.BLUE_ALLIANCE_GROUPS: - logger.debug("Validating blue user %s has alliance group assigned." % auth.user) - alliance_group, c = Group.objects.get_or_create(name=alliancename) - elif state == "MEMBER" and settings.MEMBER_ALLIANCE_GROUPS: - logger.debug("Validating member %s has alliance group assigned." % auth.user) - alliance_group, c = Group.objects.get_or_create(name=alliancename) - else: - logger.debug("Ensuring non-member %s has no alliance groups assigned." % auth.user) - else: - logger.debug("User %s main character %s not in an alliance. Ensuring no allinace group assigned." % (auth.user, char)) - if alliance_group: - if not alliance_group in auth.user.groups.all(): - logger.info("Adding user %s to alliance group %s" % (auth.user, alliance_group)) - auth.user.groups.add(alliance_group) - for g in auth.user.groups.all(): - if str.startswith(str(g.name), "Alliance_"): - if g != alliance_group: - logger.info("Removing user %s from old alliancegroup %s" % (auth.user, g)) - auth.user.groups.remove(g) - -def make_member(user): - change = False - logger.debug("Ensuring user %s has member permissions and groups." % user) - # ensure member is not blue right now - if check_if_user_has_permission(user, 'blue_member'): - logger.info("Removing user %s blue permission to transition to member" % user) - remove_member_permission(user, 'blue_member') - change = True - blue_group, c = Group.objects.get_or_create(name=settings.DEFAULT_BLUE_GROUP) - if blue_group in user.groups.all(): - logger.info("Removing user %s blue group" % user) - user.groups.remove(blue_group) - change = True - # make member - if check_if_user_has_permission(user, 'member') is False: - logger.info("Adding user %s member permission" % user) - add_member_permission(user, 'member') - change = True - member_group, c = Group.objects.get_or_create(name=settings.DEFAULT_AUTH_GROUP) - if not member_group in user.groups.all(): - logger.info("Adding user %s to member group" % user) - user.groups.add(member_group) - change = True - auth, c = AuthServicesInfo.objects.get_or_create(user=user) - if auth.is_blue: - logger.info("Marking user %s as non-blue" % user) - auth.is_blue = False - auth.save() - change = True - assign_corp_group(auth) - assign_alliance_group(auth) - return change - -def make_blue(user): - change = False - logger.debug("Ensuring user %s has blue permissions and groups." % user) - # ensure user is not a member - if check_if_user_has_permission(user, 'member'): - logger.info("Removing user %s member permission to transition to blue" % user) - remove_member_permission(user, 'blue_member') - change = True - member_group, c = Group.objects.get_or_create(name=settings.DEFAULT_AUTH_GROUP) - if member_group in user.groups.all(): - logger.info("Removing user %s member group" % user) - user.groups.remove(member_group) - change = True - # make blue - if check_if_user_has_permission(user, 'blue_member') is False: - logger.info("Adding user %s blue permission" % user) - add_member_permission(user, 'blue_member') - change = True - blue_group, c = Group.objects.get_or_create(name=settings.DEFAULT_BLUE_GROUP) - if not blue_group in user.groups.all(): - logger.info("Adding user %s to blue group" % user) - user.groups.add(blue_group) - change = True - auth, c = AuthServicesInfo.objects.get_or_create(user=user) - if auth.is_blue is False: - logger.info("Marking user %s as blue" % user) - auth.is_blue = True - auth.save() - change = True - assign_corp_group(auth) - assign_alliance_group(auth) - return change - -def determine_membership_by_character(char): - if settings.IS_CORP: - if int(char.corporation_id) == int(settings.CORP_ID): - logger.debug("Character %s in owning corp id %s" % (char, char.corporation_id)) - return "MEMBER" - else: - if int(char.alliance_id) == int(settings.ALLIANCE_ID): - logger.debug("Character %s in owning alliance id %s" % (char, char.alliance_id)) - return "MEMBER" - if EveCorporationInfo.objects.filter(corporation_id=char.corporation_id).exists() is False: - logger.debug("No corp model for character %s corp id %s. Unable to check standings. Non-member." % (char, char.corporation_id)) - return False - else: - corp = EveCorporationInfo.objects.get(corporation_id=char.corporation_id) - if corp.is_blue: - logger.debug("Character %s member of blue corp %s" % (char, corp)) - return "BLUE" - else: - logger.debug("Character %s member of non-blue corp %s. Non-member." % (char, corp)) - return False - -def determine_membership_by_user(user): - logger.debug("Determining membership of user %s" % user) - auth, c = AuthServicesInfo.objects.get_or_create(user=user) - if auth.main_char_id: - if EveCharacter.objects.filter(character_id=auth.main_char_id).exists(): - char = EveCharacter.objects.get(character_id=auth.main_char_id) - return determine_membership_by_character(char) - else: - logger.debug("Character model matching user %s main character id %s does not exist. Non-member." % (user, auth.main_char_id)) - return False - else: - logger.debug("User %s has no main character set. Non-member." % user) - return False - -def set_state(user): - if user.is_superuser: - return - change = False - if user.is_active: - state = determine_membership_by_user(user) - else: - state = False - logger.debug("Assigning user %s to state %s" % (user, state)) - if state == "MEMBER": - change = make_member(user) - elif state == "BLUE": - change = make_blue(user) - else: - change = disable_member(user) - if change: - notify(user, "Membership State Change", message="You membership state has been changed to %s" % state) - -def refresh_api(api_key_pair): - logger.debug("Running update on api key %s" % api_key_pair.api_id) - user = api_key_pair.user - if EveApiManager.api_key_is_valid(api_key_pair.api_id, api_key_pair.api_key): - #check to ensure API key meets min spec - logger.info("Determined api key %s is still active." % api_key_pair.api_id) - still_valid = True - state = determine_membership_by_user(user) - if state == "BLUE": - if settings.BLUE_API_ACCOUNT: - if not EveApiManager.check_api_is_type_account(api_key_pair.api_id, api_key_pair.api_key): - logger.info("Determined api key %s for blue user %s is no longer type account as requred." % (api_key_pair.api_id, user)) - still_valid = False - notify(user, "API Failed Validation", message="Your API key ID %s is not account-wide as required." % api_key_pair.api_id, level="danger") - if not EveApiManager.check_blue_api_is_full(api_key_pair.api_id, api_key_pair.api_key): - logger.info("Determined api key %s for blue user %s no longer meets minimum access mask as required." % (api_key_pair.api_id, user)) - still_valid = False - notify(user, "API Failed Validation", message="Your API key ID %s does not meet access mask requirements." % api_key_pair.api_id, level="danger") - elif state == "MEMBER": - if settings.MEMBER_API_ACCOUNT: - if not EveApiManager.check_api_is_type_account(api_key_pair.api_id, api_key_pair.api_key): - logger.info("Determined api key %s for user %s is no longer type account as required." % (api_key_pair.api_id, user)) - still_valid = False - notify(user, "API Failed Validation", message="Your API key ID %s is not account-wide as required." % api_key_pair.api_id, level="danger") - if not EveApiManager.check_api_is_full(api_key_pair.api_id, api_key_pair.api_key): - logger.info("Determined api key %s for user %s no longer meets minimum access mask as required." % (api_key_pair.api_id, user)) - still_valid = False - notify(user, "API Failed Validation", message="Your API key ID %s does not meet access mask requirements." % api_key_pair.api_id, level="danger") - if not still_valid: - logger.debug("API key %s has failed validation; it and its characters will be deleted." % api_key_pair.api_id) - EveManager.delete_characters_by_api_id(api_key_pair.api_id, user.id) - EveManager.delete_api_key_pair(api_key_pair.api_id, user.id) - notify(user, "API Key Deleted", message="Your API key ID %s has failed validation. It and its associated characters have been deleted." % api_key_pair.api_id, level="danger") - else: - logger.info("Determined api key %s still meets requirements." % api_key_pair.api_id) - # Update characters - characters = EveApiManager.get_characters_from_api(api_key_pair.api_id, api_key_pair.api_key) - EveManager.update_characters_from_list(characters) - new_character = False - for char in characters.result: - # Ensure we have a model for all characters on key - if not EveManager.check_if_character_exist(characters.result[char]['name']): - new_character = True - logger.debug("API key %s has a new character on the account: %s" % (api_key_pair.api_id, characters.result[char]['name'])) - if new_character: - logger.debug("Creating new character %s from api key %s" % (characters.result[char]['name'], api_key_pair.api_id)) - EveManager.create_characters_from_list(characters, user, api_key_pair.api_id) - current_chars = EveCharacter.objects.filter(api_id=api_key_pair.api_id) - for c in current_chars: - if not int(c.character_id) in characters.result: - logger.info("Character %s no longer found on API ID %s" % (c, api_key_pair.api_id)) - c.delete() - else: - logger.debug("API key %s is no longer valid; it and its characters will be deleted." % api_key_pair.api_id) - EveManager.delete_characters_by_api_id(api_key_pair.api_id, user.id) - EveManager.delete_api_key_pair(api_key_pair.api_id, user.id) - notify(user, "API Key Deleted", message="Your API key ID %s is invalid. It and its associated characters have been deleted." % api_key_pair.api_id, level="danger") - -# Run every 3 hours -@periodic_task(run_every=crontab(minute=0, hour="*/3")) -def run_api_refresh(): - users = User.objects.all() - logger.debug("Running api refresh on %s users." % len(users)) - for user in users: - # Check if the api server is online - logger.debug("Running api refresh for user %s" % user) - if EveApiManager.check_if_api_server_online(): - api_key_pairs = EveManager.get_api_key_pairs(user.id) - logger.debug("User %s has api key pairs %s" % (user, api_key_pairs)) - if api_key_pairs: - authserviceinfo, c = AuthServicesInfo.objects.get_or_create(user=user) - logger.debug("User %s has api keys. Proceeding to refresh." % user) - for api_key_pair in api_key_pairs: - try: - refresh_api(api_key_pair) - except evelink.api.APIError as e: - if int(e.code) >= 500: - logger.error("EVE API servers encountered error %s updating %s" % (e.code, api_key_pair)) - elif int(e.code) == 221: - logger.warn("API server hiccup %s while updating %s" % (e.code, api_key_pair)) - else: - logger.info("API key %s failed update with error code %s" % (api_key_pair.api_id, e.code)) - EveManager.delete_characters_by_api_id(api_key_pair.api_id, user.id) - EveManager.delete_api_key_pair(api_key_pair.api_id, user.id) - notify(user, "API Key Deleted", message="Your API key ID %s failed validation with code %s. It and its associated characters have been deleted." % (api_key_pair.api_id, e.code), level="danger") - # Check our main character - if EveCharacter.objects.filter(character_id=authserviceinfo.main_char_id).exists() is False: - logger.info("User %s main character id %s missing model. Clearning main character." % (user, authserviceinfo.main_char_id)) - authserviceinfo.main_char_id = '' - authserviceinfo.save() - notify(user, "Main Character Reset", message="Your specified main character no longer has a model.\nThis could be the result of an invalid API\nYour main character ID has been reset.", level="warn") - set_state(user) - -def populate_alliance(id, blue=False): - logger.debug("Populating alliance model with id %s blue %s" % (id, blue)) - alliance_info = EveApiManager.get_alliance_information(id) - - if not alliance_info: - raise ValueError("Supplied alliance id %s is invalid" % id) - - if EveAllianceInfo.objects.filter(alliance_id=id).exists(): - alliance = EveAllianceInfo.objects.get(alliance_id=id) - else: - EveManager.create_alliance_info(alliance_info['id'], alliance_info['name'], alliance_info['ticker'], - alliance_info['executor_id'], alliance_info['member_count'], blue) - alliance = EveAllianceInfo.objects.get(alliance_id=id) - for member_corp in alliance_info['member_corps']: - if EveCorporationInfo.objects.filter(corporation_id=member_corp).exists(): - corp = EveCorporationInfo.objects.get(corporation_id=member_corp) - if corp.alliance != alliance: - corp.alliance = alliance - corp.save() - else: - logger.info("Creating new alliance member corp id %s" % member_corp) - corpinfo = EveApiManager.get_corporation_information(member_corp) - EveManager.create_corporation_info(corpinfo['id'], corpinfo['name'], corpinfo['ticker'], - corpinfo['members']['current'], blue, alliance) - -@task -def update_alliance(id): - alliance = EveAllianceInfo.objects.get(alliance_id=id) - corps = EveCorporationInfo.objects.filter(alliance=alliance) - logger.debug("Updating alliance %s with %s member corps" % (alliance, len(corps))) - allianceinfo = EveApiManager.get_alliance_information(alliance.alliance_id) - if allianceinfo: - EveManager.update_alliance_info(allianceinfo['id'], allianceinfo['executor_id'], - allianceinfo['member_count'], alliance.is_blue) - for corp in corps: - if corp.corporation_id in allianceinfo['member_corps'] is False: - logger.info("Corp %s no longer in alliance %s" % (corp, alliance)) - corp.alliance = None - corp.save() - populate_alliance(alliance.alliance_id, blue=alliance.is_blue) - elif EveApiManager.check_if_alliance_exists(alliance.alliance_id) is False: - logger.info("Alliance %s has closed. Deleting model" % alliance) - alliance.delete() - -@task -def update_corp(id): - corp = EveCorporationInfo.objects.get(corporation_id=id) - logger.debug("Updating corp %s" % corp) - corpinfo = EveApiManager.get_corporation_information(corp.corporation_id) - if corpinfo: - alliance = None - if EveAllianceInfo.objects.filter(alliance_id=corpinfo['alliance']['id']).exists(): - alliance = EveAllianceInfo.objects.get(alliance_id=corpinfo['alliance']['id']) - EveManager.update_corporation_info(corpinfo['id'], corpinfo['members']['current'], alliance, corp.is_blue) - elif EveApiManager.check_if_corp_exists(corp.corporation_id) is False: - logger.info("Corp %s has closed. Deleting model" % corp) - corp.delete() - -# Run Every 2 hours -@periodic_task(run_every=crontab(minute=0, hour="*/2")) -def run_corp_update(): - if EveApiManager.check_if_api_server_online() is False: - logger.warn("Aborted updating corp and alliance models: API server unreachable") - return - standing_level = 'alliance' - try: - # get corp info for owning corp if required - ownercorpinfo = {} - if settings.IS_CORP: - standing_level = 'corp' - logger.debug("Getting information for owning corp with id %s" % settings.CORP_ID) - ownercorpinfo = EveApiManager.get_corporation_information(settings.CORP_ID) - if not ownercorpinfo: - logger.error("Failed to retrieve corp info for owning corp id %s - bad corp id?" % settings.CORP_ID) - return - - # check if we need to update an alliance model - alliance_id = '' - if ownercorpinfo and ownercorpinfo['alliance']['id']: - alliance_id = ownercorpinfo['alliance']['id'] - elif settings.IS_CORP is False: - alliance_id = settings.ALLIANCE_ID - - # get and create alliance info for owning alliance if required - alliance = None - if alliance_id: - logger.debug("Getting information for owning alliance with id %s" % alliance_id) - ownerallianceinfo = EveApiManager.get_alliance_information(alliance_id) - if not ownerallianceinfo: - logger.error("Failed to retrieve corp info for owning alliance id %s - bad alliance id?" % alliance_id) - return - if EveAllianceInfo.objects.filter(alliance_id=ownerallianceinfo['id']).exists(): - logger.debug("Updating existing owner alliance model with id %s" % alliance_id) - EveManager.update_alliance_info(ownerallianceinfo['id'], ownerallianceinfo['executor_id'], ownerallianceinfo['member_count'], False) - else: - populate_alliance(alliance_id) - alliance = EveAllianceInfo.objects.get(alliance_id=alliance_id) - - # create corp info for owning corp if required - if ownercorpinfo: - if EveCorporationInfo.objects.filter(corporation_id=ownercorpinfo['id']).exists(): - logger.debug("Updating existing owner corp model with id %s" % ownercorpinfo['id']) - EveManager.update_corporation_info(ownercorpinfo['id'], ownercorpinfo['members']['current'], alliance, False) - else: - logger.info("Creating model for owning corp with id %s" % ownercorpinfo['id']) - EveManager.create_corporation_info(ownercorpinfo['id'], ownercorpinfo['name'], ownercorpinfo['ticker'], - ownercorpinfo['members']['current'], False, alliance) - - # validate and create corp models for member corps of owning alliance - if alliance: - current_corps = EveCorporationInfo.objects.filter(alliance=alliance) - for corp in current_corps: - if corp.corporation_id in ownerallianceinfo['member_corps'] is False: - logger.info("Corp %s is no longer in owning alliance %s - updating model." % (corp, alliance)) - corp.alliance = None - corp.save() - for member_corp in ownerallianceinfo['member_corps']: - if EveCorporationInfo.objects.filter(corporation_id=member_corp).exists(): - corp = EveCorporationInfo.objects.get(corporation_id=member_corp) - if corp.alliance == alliance is not True: - logger.info("Associating corp %s with owning alliance %s" % (corp, alliance)) - corp.alliance = alliance - corp.save() - else: - corpinfo = EveApiManager.get_corporation_information(member_corp) - logger.info("Creating model for owning alliance member corp with id %s" % corpinfo['id']) - EveManager.create_corporation_info(corpinfo['id'], corpinfo['name'], corpinfo['ticker'], - corpinfo['members']['current'], False, alliance) - - # update existing corp models - for corp in EveCorporationInfo.objects.all(): - update_corp.delay(corp.corporation_id) - - # update existing alliance models - for alliance in EveAllianceInfo.objects.all(): - update_alliance.delay(alliance.alliance_id) - - # create standings - standings = EveApiManager.get_corp_standings() - if standings: - standings = standings[standing_level] - for standing in standings: - if int(standings[standing]['standing']) >= settings.BLUE_STANDING: - logger.debug("Standing %s meets threshold" % standing) - if EveApiManager.check_if_id_is_alliance(standing): - logger.debug("Standing %s is an alliance" % standing) - if EveAllianceInfo.objects.filter(alliance_id=standing).exists(): - alliance = EveAllianceInfo.objects.get(alliance_id=standing) - if alliance.is_blue is not True: - logger.info("Updating alliance %s as blue" % alliance) - alliance.is_blue = True - alliance.save() - else: - populate_alliance(standing, blue=True) - elif EveApiManager.check_if_id_is_corp(standing): - logger.debug("Standing %s is a corp" % standing) - if EveCorporationInfo.objects.filter(corporation_id=standing).exists(): - corp = EveCorporationInfo.objects.get(corporation_id=standing) - if corp.is_blue is not True: - logger.info("Updating corp %s as blue" % corp) - corp.is_blue = True - corp.save() - else: - logger.info("Creating model for blue corp with id %s" % standing) - corpinfo = EveApiManager.get_corporation_information(standing) - corp_alliance = None - if EveAllianceInfo.objects.filter(alliance_id=corpinfo['alliance']['id']).exists(): - logger.debug("New corp model for standing %s has existing alliance model" % standing) - corp_alliance = EveAllianceInfo.objects.get(alliance_id=corpinfo['alliance']['id']) - EveManager.create_corporation_info(corpinfo['id'], corpinfo['name'], corpinfo['ticker'], - corpinfo['members']['current'], True, corp_alliance) - - - # update alliance standings - for alliance in EveAllianceInfo.objects.filter(is_blue=True): - if int(alliance.alliance_id) in standings: - if float(standings[int(alliance.alliance_id)]['standing']) < float(settings.BLUE_STANDING): - logger.info("Alliance %s no longer meets minimum blue standing threshold" % alliance) - alliance.is_blue = False - alliance.save() - else: - logger.info("Alliance %s no longer in standings" % alliance) - alliance.is_blue = False - alliance.save() - - # update corp standings - for corp in EveCorporationInfo.objects.filter(is_blue=True): - if int(corp.corporation_id) in standings: - if float(standings[int(corp.corporation_id)]['standing']) < float(settings.BLUE_STANDING): - logger.info("Corp %s no longer meets minimum blue standing threshold" % corp) - corp.is_blue = False - corp.save() - else: - if corp.alliance: - if not corp.alliance.is_blue: - logger.info("Corp %s and its alliance %s are no longer blue" % (corp, corp.alliance)) - corp.is_blue = False - corp.save() - else: - logger.info("Corp %s is no longer blue" % corp) - corp.is_blue = False - corp.save() - - # delete unnecessary alliance models - for alliance in EveAllianceInfo.objects.filter(is_blue=False): - logger.debug("Checking to delete alliance %s" % alliance) - if not settings.IS_CORP: - if not alliance.alliance_id == settings.ALLIANCE_ID: - logger.info("Deleting unnecessary alliance model %s" % alliance) - alliance.delete() - else: - if not alliance.evecorporationinfo_set.filter(corporation_id=settings.CORP_ID).exists(): - logger.info("Deleting unnecessary alliance model %s" % alliance) - alliance.delete() - - # delete unnecessary corp models - for corp in EveCorporationInfo.objects.filter(is_blue=False): - logger.debug("Checking to delete corp %s" % corp) - if not settings.IS_CORP: - if corp.alliance: - logger.debug("Corp %s has alliance %s" % (corp, corp.alliance)) - if not corp.alliance.alliance_id == settings.ALLIANCE_ID: - logger.info("Deleting unnecessary corp model %s" % corp) - corp.delete() - else: - logger.info("Deleting unnecessary corp model %s" % corp) - corp.delete() - else: - if corp.corporation_id != settings.CORP_ID: - logger.debug("Corp %s is not owning corp" % corp) - if corp.alliance: - logger.debug("Corp %s has alliance %s" % (corp, corp.alliance)) - if not corp.alliance.evecorporationinfo_set.filter(corporation_id=settings.CORP_ID).exists(): - logger.info("Deleting unnecessary corp model %s" % corp) - corp.delete() - else: - logger.info("Deleting unnecessary corp model %s" % corp) - corp.delete() - else: - logger.debug("Corp %s is owning corp" % corp) - except evelink.api.APIError as e: - logger.error("Model update failed with error code %s" % e.code) - -@periodic_task(run_every=crontab(minute="*/30")) -def run_ts3_group_update(): - if is_teamspeak3_active(): - logger.debug("TS3 installed. Syncing local group objects.") - Teamspeak3Manager._sync_ts_group_db() diff --git a/celerytask/tests.py b/celerytask/tests.py deleted file mode 100644 index a39b155a..00000000 --- a/celerytask/tests.py +++ /dev/null @@ -1 +0,0 @@ -# Create your tests here. diff --git a/celerytask/views.py b/celerytask/views.py deleted file mode 100644 index 60f00ef0..00000000 --- a/celerytask/views.py +++ /dev/null @@ -1 +0,0 @@ -# Create your views here. diff --git a/corputils/__init__.py b/corputils/__init__.py index e69de29b..baffc488 100644 --- a/corputils/__init__.py +++ b/corputils/__init__.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/corputils/admin.py b/corputils/admin.py index e69de29b..baffc488 100644 --- a/corputils/admin.py +++ b/corputils/admin.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/corputils/apps.py b/corputils/apps.py new file mode 100644 index 00000000..677d5fcb --- /dev/null +++ b/corputils/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class CorpUtilsConfig(AppConfig): + name = 'corputils' diff --git a/corputils/forms.py b/corputils/forms.py index d58129f9..0a05bd8a 100644 --- a/corputils/forms.py +++ b/corputils/forms.py @@ -1,9 +1,8 @@ +from __future__ import unicode_literals from django import forms -from django.conf import settings from django.utils.translation import ugettext_lazy as _ -from eveonline.models import EveCorporationInfo -from eveonline.models import EveAllianceInfo class CorputilsSearchForm(forms.Form): - search_string = forms.CharField(max_length=254, required=True, label="", widget=forms.TextInput(attrs={'placeholder': _('Search characters...')})) + search_string = forms.CharField(max_length=254, required=True, label="", + widget=forms.TextInput(attrs={'placeholder': _('Search characters...')})) diff --git a/corputils/models.py b/corputils/models.py index e69de29b..baffc488 100644 --- a/corputils/models.py +++ b/corputils/models.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/corputils/views.py b/corputils/views.py index 5038a961..99335206 100644 --- a/corputils/views.py +++ b/corputils/views.py @@ -1,12 +1,11 @@ +from __future__ import unicode_literals from django.conf import settings -from django.shortcuts import render_to_response -from django.template import RequestContext from django.contrib.auth.decorators import login_required -from django.shortcuts import HttpResponseRedirect +from django.shortcuts import render, redirect from collections import namedtuple -from authentication.managers import AuthServicesInfoManager +from authentication.models import AuthServicesInfo from services.managers.eve_api_manager import EveApiManager from services.managers.evewho_manager import EveWhoManager from eveonline.models import EveCorporationInfo @@ -14,14 +13,15 @@ from eveonline.models import EveAllianceInfo from eveonline.models import EveCharacter from eveonline.models import EveApiKeyPair from fleetactivitytracking.models import Fat -from util import check_if_user_has_permission -from forms import CorputilsSearchForm +from corputils.forms import CorputilsSearchForm from evelink.api import APIError import logging import datetime logger = logging.getLogger(__name__) + + class Player(object): def __init__(self, main, user, maincorp, maincorpid, altlist, apilist, n_fats): self.main = main @@ -32,21 +32,23 @@ class Player(object): self.apilist = apilist self.n_fats = n_fats + def first_day_of_next_month(year, month): if month == 12: - return datetime.datetime(year+1,1,1) + return datetime.datetime(year + 1, 1, 1) else: - return datetime.datetime(year, month+1, 1) + return datetime.datetime(year, month + 1, 1) + def first_day_of_previous_month(year, month): if month == 1: - return datetime.datetime(year-1,12,1) + return datetime.datetime(year - 1, 12, 1) else: - return datetime.datetime(year, month-1, 1) + return datetime.datetime(year, month - 1, 1) @login_required -def corp_member_view(request, corpid = None, year=datetime.date.today().year, month=datetime.date.today().month): +def corp_member_view(request, corpid=None, year=datetime.date.today().year, month=datetime.date.today().month): year = int(year) month = int(month) start_of_month = datetime.datetime(year, month, 1) @@ -55,16 +57,17 @@ def corp_member_view(request, corpid = None, year=datetime.date.today().year, mo logger.debug("corp_member_view called by user %s" % request.user) try: - user_main = EveCharacter.objects.get(character_id=AuthServicesInfoManager.get_auth_service_info(user=request.user).main_char_id) + user_main = EveCharacter.objects.get( + character_id=AuthServicesInfo.objects.get_or_create(user=request.user)[0].main_char_id) user_corp_id = int(user_main.corporation_id) except (ValueError, EveCharacter.DoesNotExist): user_corp_id = settings.CORP_ID - if not settings.IS_CORP: alliance = EveAllianceInfo.objects.get(alliance_id=settings.ALLIANCE_ID) alliancecorps = EveCorporationInfo.objects.filter(alliance=alliance) - membercorplist = [(int(membercorp.corporation_id), str(membercorp.corporation_name)) for membercorp in alliancecorps] + membercorplist = [(int(membercorp.corporation_id), str(membercorp.corporation_name)) for membercorp in + alliancecorps] membercorplist.sort(key=lambda tup: tup[1]) membercorp_id_list = [int(membercorp.corporation_id) for membercorp in alliancecorps] @@ -77,7 +80,7 @@ def corp_member_view(request, corpid = None, year=datetime.date.today().year, mo user_corp_id = None if not corpid: - if(settings.IS_CORP): + if settings.IS_CORP: corpid = settings.CORP_ID elif user_corp_id: corpid = user_corp_id @@ -86,7 +89,8 @@ def corp_member_view(request, corpid = None, year=datetime.date.today().year, mo corp = EveCorporationInfo.objects.get(corporation_id=corpid) - if check_if_user_has_permission(request.user, 'alliance_apis') or (check_if_user_has_permission(request.user, 'corp_apis') and (user_corp_id == corpid)): + if request.user.has_perm('auth.alliance_apis') or ( + request.user.has_perm('auth.corp_apis') and (user_corp_id == corpid)): logger.debug("Retreiving and sending API-information") if settings.IS_CORP: @@ -107,7 +111,7 @@ def corp_member_view(request, corpid = None, year=datetime.date.today().year, mo char = EveCharacter.objects.get(character_id=char_id) char_owner = char.user try: - mainid = int(AuthServicesInfoManager.get_auth_service_info(user=char_owner).main_char_id) + mainid = int(AuthServicesInfo.objects.get_or_create(user=char_owner)[0].main_char_id) mainchar = EveCharacter.objects.get(character_id=mainid) mainname = mainchar.character_name maincorp = mainchar.corporation_name @@ -120,7 +124,7 @@ def corp_member_view(request, corpid = None, year=datetime.date.today().year, mo maincorp = "Not set." maincorpid = None api_pair = None - num_registered_characters = num_registered_characters + 1 + num_registered_characters += 1 characters_with_api.setdefault(mainname, Player(main=mainchar, user=char_owner, maincorp=maincorp, @@ -132,7 +136,7 @@ def corp_member_view(request, corpid = None, year=datetime.date.today().year, mo if api_pair: characters_with_api[mainname].apilist.append(api_pair) - except (EveCharacter.DoesNotExist): + except EveCharacter.DoesNotExist: characters_without_api.update({member_data["name"]: member_data["id"]}) for char in EveCharacter.objects.filter(corporation_id=corpid): @@ -140,7 +144,7 @@ def corp_member_view(request, corpid = None, year=datetime.date.today().year, mo logger.info("Character '%s' does not exist in EveWho dump." % char.character_name) char_owner = char.user try: - mainid = int(AuthServicesInfoManager.get_auth_service_info(user=char_owner).main_char_id) + mainid = int(AuthServicesInfo.objects.get_or_create(user=char_owner)[0].main_char_id) mainchar = EveCharacter.objects.get(character_id=mainid) mainname = mainchar.character_name maincorp = mainchar.corporation_name @@ -153,7 +157,7 @@ def corp_member_view(request, corpid = None, year=datetime.date.today().year, mo maincorp = "Not set." maincorpid = None api_pair = None - num_registered_characters = num_registered_characters + 1 + num_registered_characters += 1 characters_with_api.setdefault(mainname, Player(main=mainchar, user=char_owner, maincorp=maincorp, @@ -168,13 +172,13 @@ def corp_member_view(request, corpid = None, year=datetime.date.today().year, mo n_unacounted = corp.member_count - (num_registered_characters + len(characters_without_api)) for mainname, player in characters_with_api.items(): - fats_this_month = Fat.objects.filter(user=player.user).filter(fatlink__fatdatetime__gte = start_of_month).filter(fatlink__fatdatetime__lt = start_of_next_month) + fats_this_month = Fat.objects.filter(user=player.user).filter( + fatlink__fatdatetime__gte=start_of_month).filter(fatlink__fatdatetime__lt=start_of_next_month) characters_with_api[mainname].n_fats = len(fats_this_month) if start_of_next_month > datetime.datetime.now(): start_of_next_month = None - if not settings.IS_CORP: context = {"membercorplist": membercorplist, "corp": corp, @@ -196,8 +200,8 @@ def corp_member_view(request, corpid = None, year=datetime.date.today().year, mo context["previous_month"] = start_of_previous_month context["this_month"] = start_of_month - return render_to_response('registered/corputils.html',context, context_instance=RequestContext(request) ) - return HttpResponseRedirect("/dashboard/") + return render(request, 'registered/corputils.html', context=context) + return redirect("auth_dashboard") @login_required @@ -208,13 +212,15 @@ def corputils_search(request, corpid=settings.CORP_ID): authorized = False try: - user_main = EveCharacter.objects.get(character_id=AuthServicesInfoManager.get_auth_service_info(user=request.user).main_char_id) - if check_if_user_has_permission(request.user, 'alliance_apis') or (check_if_user_has_permission(request.user, 'corp_apis') and (user_main.corporation_id == corpid)): + user_main = EveCharacter.objects.get( + character_id=AuthServicesInfo.objects.get_or_create(user=request.user)[0].main_char_id) + if request.user.has_perm('auth.alliance_apis') or ( + request.user.has_perm('auth.corp_apis') and (user_main.corporation_id == corpid)): logger.debug("Retreiving and sending API-information") authorized = True except (ValueError, EveCharacter.DoesNotExist): - if check_if_user_has_permission(request.user, 'alliance_apis'): - logger.debug("Retreiving and sending API-information") + if request.user.has_perm('auth.alliance_apis'): + logger.debug("Retrieving and sending API-information") authorized = True if authorized: @@ -229,14 +235,16 @@ def corputils_search(request, corpid=settings.CORP_ID): if settings.IS_CORP: try: - member_list = EveApiManager.get_corp_membertracking(settings.CORP_API_ID, settings.CORP_API_VCODE) + member_list = EveApiManager.get_corp_membertracking(settings.CORP_API_ID, + settings.CORP_API_VCODE) except APIError: logger.debug("Corp API does not have membertracking scope, using EveWho data instead.") member_list = EveWhoManager.get_corporation_members(corpid) else: member_list = EveWhoManager.get_corporation_members(corpid) - SearchResult = namedtuple('SearchResult', ['name', 'id', 'main', 'api_registered', 'character', 'apiinfo']) + SearchResult = namedtuple('SearchResult', + ['name', 'id', 'main', 'api_registered', 'character', 'apiinfo']) searchresults = [] for memberid, member_data in member_list.items(): @@ -244,7 +252,7 @@ def corputils_search(request, corpid=settings.CORP_ID): try: char = EveCharacter.objects.get(character_name=member_data["name"]) user = char.user - mainid = int(AuthServicesInfoManager.get_auth_service_info(user=user).main_char_id) + mainid = int(AuthServicesInfo.objects.get_or_create(user=user)[0].main_char_id) main = EveCharacter.objects.get(character_id=mainid) api_registered = True apiinfo = EveApiKeyPair.objects.get(api_id=char.api_id) @@ -254,25 +262,24 @@ def corputils_search(request, corpid=settings.CORP_ID): main = "" apiinfo = None - searchresults.append(SearchResult(name=member_data["name"], id=memberid, main=main, api_registered=api_registered, - character=char, apiinfo=apiinfo)) + searchresults.append(SearchResult(name=member_data["name"], id=memberid, main=main, + api_registered=api_registered, + character=char, apiinfo=apiinfo)) + logger.info("Found %s members for user %s matching search string %s" % ( + len(searchresults), request.user, searchstring)) - logger.info("Found %s members for user %s matching search string %s" % (len(searchresults), request.user, searchstring)) + context = {'corp': corp, 'results': searchresults, 'search_form': CorputilsSearchForm(), + "year": datetime.datetime.now().year, "month": datetime.datetime.now().month} - context = {'corp': corp, 'results': searchresults, 'search_form': CorputilsSearchForm(), "year":datetime.datetime.now().year, "month":datetime.datetime.now().month} - - return render_to_response('registered/corputilssearchview.html', - context, context_instance=RequestContext(request)) + return render(request, 'registered/corputilssearchview.html', + context=context) else: logger.debug("Form invalid - returning for user %s to retry." % request.user) context = {'corp': corp, 'members': None, 'search_form': CorputilsSearchForm()} - return render_to_response('registered/corputilssearchview.html', - context, context_instance=RequestContext(request)) + return render(request, 'registered/corputilssearchview.html', context=context) else: logger.debug("Returning empty search form for user %s" % request.user) - return HttpResponseRedirect("/corputils/") - return HttpResponseRedirect("/dashboard/") - - + return redirect("auth_corputils") + return redirect("auth_dashboard") diff --git a/eveonline/__init__.py b/eveonline/__init__.py index e69de29b..baffc488 100644 --- a/eveonline/__init__.py +++ b/eveonline/__init__.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/eveonline/admin.py b/eveonline/admin.py index 7b0e7f22..5586c875 100644 --- a/eveonline/admin.py +++ b/eveonline/admin.py @@ -1,24 +1,28 @@ +from __future__ import unicode_literals from django.contrib import admin -from models import EveCharacter -from models import EveApiKeyPair -from models import EveAllianceInfo -from models import EveCorporationInfo -from authentication.managers import AuthServicesInfoManager +from eveonline.models import EveCharacter +from eveonline.models import EveApiKeyPair +from eveonline.models import EveAllianceInfo +from eveonline.models import EveCorporationInfo +from authentication.models import AuthServicesInfo admin.site.register(EveAllianceInfo) admin.site.register(EveCorporationInfo) + class EveApiKeyPairAdmin(admin.ModelAdmin): search_fields = ['api_id', 'user__username'] list_display = ['api_id', 'user'] + class EveCharacterAdmin(admin.ModelAdmin): search_fields = ['character_name', 'corporation_name', 'alliance_name', 'user__username', 'api_id'] list_display = ('character_name', 'corporation_name', 'alliance_name', 'user', 'main_character') - def main_character(self, obj): - auth = AuthServicesInfoManager.get_auth_service_info(obj.user) + @staticmethod + def main_character(obj): + auth = AuthServicesInfo.objects.get_or_create(user=obj.user)[0] if auth and auth.main_char_id: try: return EveCharacter.objects.get(character_id=auth.main_char_id) @@ -26,5 +30,6 @@ class EveCharacterAdmin(admin.ModelAdmin): pass return None + admin.site.register(EveCharacter, EveCharacterAdmin) admin.site.register(EveApiKeyPair, EveApiKeyPairAdmin) diff --git a/eveonline/apps.py b/eveonline/apps.py new file mode 100644 index 00000000..866e59e8 --- /dev/null +++ b/eveonline/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class EveonlineConfig(AppConfig): + name = 'eveonline' diff --git a/eveonline/forms.py b/eveonline/forms.py index eff7a873..7588fdbc 100644 --- a/eveonline/forms.py +++ b/eveonline/forms.py @@ -1,23 +1,24 @@ +from __future__ import unicode_literals from django import forms from django.conf import settings from services.managers.eve_api_manager import EveApiManager from eveonline.managers import EveManager -from eveonline.models import EveCharacter import evelink -from celerytask.tasks import determine_membership_by_character - import logging logger = logging.getLogger(__name__) -class UpdateKeyForm(forms.Form): - user_state = None +class UpdateKeyForm(forms.Form): api_id = forms.CharField(max_length=254, required=True, label="Key ID") api_key = forms.CharField(max_length=254, required=True, label="Verification Code") - + + def __init__(self, user, *args, **kwargs): + super(UpdateKeyForm, self).__init__(*args, **kwargs) + self.user = user + def clean_api_id(self): try: api_id = int(self.cleaned_data['api_id']) @@ -28,38 +29,21 @@ class UpdateKeyForm(forms.Form): def clean(self): super(UpdateKeyForm, self).clean() - if 'api_id' in self.cleaned_data and 'api_key' in self.cleaned_data: - try: - if EveManager.check_if_api_key_pair_exist(self.cleaned_data['api_id']): - logger.debug("UpdateKeyForm failed cleaning as API id %s already exists." % self.cleaned_data['api_id']) - raise forms.ValidationError(u'API key already exist') - if EveApiManager.api_key_is_valid(self.cleaned_data['api_id'], self.cleaned_data['api_key']) is False: - raise forms.ValidationError(u'API key is invalid') - if (settings.REJECT_OLD_APIS and - EveManager.check_if_api_key_pair_is_new(self.cleaned_data['api_id'], settings.REJECT_OLD_APIS_MARGIN) is False): - raise forms.ValidationError(u'API key is too old. Please create a new key') - chars = EveApiManager.get_characters_from_api(self.cleaned_data['api_id'], self.cleaned_data['api_key']).result - states = [] - states.append(self.user_state) - for char in chars: - evechar = EveCharacter() - evechar.character_name = chars[char]['name'] - evechar.corporation_id = chars[char]['corp']['id'] - evechar.alliance_id = chars[char]['alliance']['id'] - state = determine_membership_by_character(evechar) - logger.debug("API ID %s character %s has state %s" % (self.cleaned_data['api_id'], evechar, state)) - states.append(state) - - if 'MEMBER' in states: - if EveApiManager.validate_member_api(self.cleaned_data['api_id'], self.cleaned_data['api_key']) is False: - raise forms.ValidationError(u'API must meet member requirements') - if 'BLUE' in states: - if EveApiManager.validate_blue_api(self.cleaned_data['api_id'], self.cleaned_data['api_key']) is False: - raise forms.ValidationError(u'API must meet blue requirements') - return self.cleaned_data - except evelink.api.APIError as e: - logger.debug("Got error code %s while validating API %s" % (e.code, self.cleaned_data['api_id'])) - if int(e.code) in [221, 222]: - raise forms.ValidationError("API key failed validation") - else: - raise forms.ValidationError("Failed to reach API servers") + if EveManager.check_if_api_key_pair_exist(self.cleaned_data['api_id']): + logger.debug("UpdateKeyForm failed cleaning as API id %s already exists." % self.cleaned_data['api_id']) + raise forms.ValidationError('API key already exist') + if settings.REJECT_OLD_APIS and not EveManager.check_if_api_key_pair_is_new( + self.cleaned_data['api_id'], + settings.REJECT_OLD_APIS_MARGIN): + raise forms.ValidationError('API key is too old. Please create a new key') + try: + EveApiManager.validate_api(self.cleaned_data['api_id'], self.cleaned_data['api_key'], self.user) + return self.cleaned_data + except EveApiManager.ApiValidationError as e: + raise forms.ValidationError(str(e)) + except evelink.api.APIError as e: + logger.debug("Got error code %s while validating API %s" % (e.code, self.cleaned_data['api_id'])) + if int(e.code) in [221, 222]: + raise forms.ValidationError("API key failed validation") + else: + raise forms.ValidationError("Failed to reach API servers") diff --git a/eveonline/managers.py b/eveonline/managers.py index ebf249c6..214433e4 100644 --- a/eveonline/managers.py +++ b/eveonline/managers.py @@ -1,13 +1,15 @@ -from models import EveCharacter -from models import EveApiKeyPair -from models import EveAllianceInfo -from models import EveCorporationInfo +from __future__ import unicode_literals +from eveonline.models import EveCharacter +from eveonline.models import EveApiKeyPair +from eveonline.models import EveAllianceInfo +from eveonline.models import EveCorporationInfo from services.managers.eve_api_manager import EveApiManager import logging logger = logging.getLogger(__name__) + class EveManager: def __init__(self): pass @@ -64,8 +66,8 @@ class EveManager: eve_char.save() logger.info("Updated character model %s" % eve_char) else: - logger.warn("Attempting to update non-existing character model with name %s" % chars.result[char]['name']) - + logger.warn( + "Attempting to update non-existing character model with name %s" % chars.result[char]['name']) @staticmethod def create_api_keypair(api_id, api_key, user_id): @@ -163,10 +165,10 @@ class EveManager: return True latest_api_id = int(EveApiKeyPair.objects.order_by('-api_id')[0].api_id) - fudge_factor if latest_api_id >= api_id: - logger.debug("api key (%d) is older than latest API key (%d). Rejecting" % (api_id, latest_api_id) ) + logger.debug("api key (%d) is older than latest API key (%d). Rejecting" % (api_id, latest_api_id)) return False else: - logger.debug("api key (%d) is new. Accepting" % api_id ) + logger.debug("api key (%d) is new. Accepting" % api_id) return True @staticmethod @@ -179,7 +181,9 @@ class EveManager: logger.info("Deleted user %s api key id %s" % (user_id, api_id)) apikeypair.delete() else: - logger.error("Unable to delete api: user mismatch: key id %s owned by user id %s, not deleting user id %s" % (api_id, apikeypair.user.id, user_id)) + logger.error( + "Unable to delete api: user mismatch: key id %s owned by user id %s, not deleting user id %s" % ( + api_id, apikeypair.user.id, user_id)) else: logger.warn("Unable to locate api id %s - cannot delete." % api_id) @@ -195,7 +199,10 @@ class EveManager: logger.info("Deleting user %s character %s from api %s" % (user_id, char, api_id)) char.delete() else: - logger.error("Unable to delete character %s by api %s: user mismatch: character owned by user id%s, not deleting user id %s" % (char, api_id, char.user.id, user_id)) + logger.error( + "Unable to delete character %s by api %s: user mismatch: character owned by user id %s, " + "not deleting user id %s" % ( + char, api_id, char.user.id, user_id)) @staticmethod def check_if_character_exist(char_name): diff --git a/eveonline/migrations/0001_initial.py b/eveonline/migrations/0001_initial.py new file mode 100644 index 00000000..cf3ebde0 --- /dev/null +++ b/eveonline/migrations/0001_initial.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-05 21:39 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='EveAllianceInfo', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('alliance_id', models.CharField(max_length=254)), + ('alliance_name', models.CharField(max_length=254)), + ('alliance_ticker', models.CharField(max_length=254)), + ('executor_corp_id', models.CharField(max_length=254)), + ('is_blue', models.BooleanField(default=False)), + ('member_count', models.IntegerField()), + ], + ), + migrations.CreateModel( + name='EveApiKeyPair', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('api_id', models.CharField(max_length=254)), + ('api_key', models.CharField(max_length=254)), + ('error_count', models.PositiveIntegerField(default=0)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='EveCharacter', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('character_id', models.CharField(max_length=254)), + ('character_name', models.CharField(max_length=254)), + ('corporation_id', models.CharField(max_length=254)), + ('corporation_name', models.CharField(max_length=254)), + ('corporation_ticker', models.CharField(max_length=254)), + ('alliance_id', models.CharField(max_length=254)), + ('alliance_name', models.CharField(max_length=254)), + ('api_id', models.CharField(max_length=254)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='EveCorporationInfo', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('corporation_id', models.CharField(max_length=254)), + ('corporation_name', models.CharField(max_length=254)), + ('corporation_ticker', models.CharField(max_length=254)), + ('member_count', models.IntegerField()), + ('is_blue', models.BooleanField(default=False)), + ('alliance', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='eveonline.EveAllianceInfo')), + ], + ), + ] diff --git a/eveonline/migrations/0002_remove_eveapikeypair_error_count.py b/eveonline/migrations/0002_remove_eveapikeypair_error_count.py new file mode 100644 index 00000000..52fca062 --- /dev/null +++ b/eveonline/migrations/0002_remove_eveapikeypair_error_count.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-10 20:20 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('eveonline', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='eveapikeypair', + name='error_count', + ), + ] diff --git a/registration/__init__.py b/eveonline/migrations/__init__.py similarity index 100% rename from registration/__init__.py rename to eveonline/migrations/__init__.py diff --git a/eveonline/models.py b/eveonline/models.py index f55b4b11..f3926a6f 100644 --- a/eveonline/models.py +++ b/eveonline/models.py @@ -1,7 +1,10 @@ +from __future__ import unicode_literals +from django.utils.encoding import python_2_unicode_compatible from django.db import models from django.contrib.auth.models import User +@python_2_unicode_compatible class EveCharacter(models.Model): character_id = models.CharField(max_length=254) character_name = models.CharField(max_length=254) @@ -17,16 +20,17 @@ class EveCharacter(models.Model): return self.character_name +@python_2_unicode_compatible class EveApiKeyPair(models.Model): api_id = models.CharField(max_length=254) api_key = models.CharField(max_length=254) user = models.ForeignKey(User) - error_count = models.PositiveIntegerField(default=0) def __str__(self): return self.user.username + " - ApiKeyPair" +@python_2_unicode_compatible class EveAllianceInfo(models.Model): alliance_id = models.CharField(max_length=254) alliance_name = models.CharField(max_length=254) @@ -39,6 +43,7 @@ class EveAllianceInfo(models.Model): return self.alliance_name +@python_2_unicode_compatible class EveCorporationInfo(models.Model): corporation_id = models.CharField(max_length=254) corporation_name = models.CharField(max_length=254) diff --git a/eveonline/tasks.py b/eveonline/tasks.py new file mode 100644 index 00000000..48ee7c89 --- /dev/null +++ b/eveonline/tasks.py @@ -0,0 +1,346 @@ +from __future__ import unicode_literals +from django.conf import settings +from celery.task import periodic_task +from django.contrib.auth.models import User +from notifications import notify +from celery import task +from celery.task.schedules import crontab +from authentication.models import AuthServicesInfo +from eveonline.managers import EveManager +from eveonline.models import EveApiKeyPair +from services.managers.eve_api_manager import EveApiManager +from eveonline.models import EveCharacter +from eveonline.models import EveCorporationInfo +from eveonline.models import EveAllianceInfo +from authentication.tasks import set_state +import logging +import evelink + +logger = logging.getLogger(__name__) + + +@task +def refresh_api(api): + logger.debug('Running update on api key %s' % api.api_id) + still_valid = True + try: + EveApiManager.validate_api(api.api_id, api.api_key, api.user) + # Update characters + characters = EveApiManager.get_characters_from_api(api.api_id, api.api_key) + EveManager.update_characters_from_list(characters) + new_character = False + for char in characters.result: + # Ensure we have a model for all characters on key + if not EveManager.check_if_character_exist(characters.result[char]['name']): + logger.debug( + "API key %s has a new character on the account: %s" % (api.api_id, characters.result[char]['name'])) + new_character = True + if new_character: + logger.debug("Creating new character %s from api key %s" % (characters.result[char]['name'], api.api_id)) + EveManager.create_characters_from_list(characters, api.user, api.api_id) + current_chars = EveCharacter.objects.filter(api_id=api.api_id) + for c in current_chars: + if not int(c.character_id) in characters.result: + logger.info("Character %s no longer found on API ID %s" % (c, api.api_id)) + c.delete() + except evelink.api.APIError as e: + logger.warning('Received unexpected APIError (%s) while updating API %s' % (e.code, api.api_id)) + except EveApiManager.ApiInvalidError: + logger.debug("API key %s is no longer valid; it and its characters will be deleted." % api.api_id) + notify(api.user, "API Failed Validation", message="Your API key ID %s is no longer valid." % api.api_id, + level="danger") + still_valid = False + except EveApiManager.ApiAccountValidationError: + logger.info( + "Determined api key %s for user %s no longer meets account access requirements." % (api.api_id, api.user)) + notify(api.user, "API Failed Validation", + message="Your API key ID %s is no longer account-wide as required." % api.api_id, level="danger") + still_valid = False + except EveApiManager.ApiMaskValidationError as e: + logger.info("Determined api key %s for user %s no longer meets minimum access mask as required." % ( + api.api_id, api.user)) + notify(api.user, "API Failed Validation", + message="Your API key ID %s no longer meets access mask requirements. Required: %s Got: %s" % ( + api.api_id, e.required_mask, e.api_mask), level="danger") + still_valid = False + finally: + if not still_valid: + EveManager.delete_characters_by_api_id(api.api_id, api.user.id) + EveManager.delete_api_key_pair(api.api_id, api.user.id) + notify(api.user, "API Key Deleted", + message="Your API key ID %s is invalid. It and its associated characters have been deleted." % api.api_id, + level="danger") + + +@task +def refresh_user_apis(user): + logger.debug('Refreshing all APIs belonging to user %s' % user) + apis = EveApiKeyPair.objects.filter(user=user) + for x in apis: + refresh_api(x) + # Check our main character + auth = AuthServicesInfo.objects.get_or_create(user=user)[0] + if auth.main_char_id: + if EveCharacter.objects.filter(character_id=auth.main_char_id).exists() is False: + logger.info( + "User %s main character id %s missing model. Clearning main character." % (user, auth.main_char_id)) + auth.main_char_id = '' + auth.save() + notify(user, "Main Character Reset", + message="Your specified main character no longer has a model.\nThis could be the result of " + "an invalid API.\nYour main character ID has been reset.", + level="warn") + set_state(user) + + +@periodic_task(run_every=crontab(minute=0, hour="*/3")) +def run_api_refresh(): + for u in User.objects.all(): + refresh_user_apis.delay(u) + + +def populate_alliance(id, blue=False): + logger.debug("Populating alliance model with id %s blue %s" % (id, blue)) + alliance_info = EveApiManager.get_alliance_information(id) + + if not alliance_info: + raise ValueError("Supplied alliance id %s is invalid" % id) + + if not EveAllianceInfo.objects.filter(alliance_id=id).exists(): + EveManager.create_alliance_info(alliance_info['id'], alliance_info['name'], alliance_info['ticker'], + alliance_info['executor_id'], alliance_info['member_count'], blue) + alliance = EveAllianceInfo.objects.get(alliance_id=id) + for member_corp in alliance_info['member_corps']: + if EveCorporationInfo.objects.filter(corporation_id=member_corp).exists(): + corp = EveCorporationInfo.objects.get(corporation_id=member_corp) + if corp.alliance != alliance: + corp.alliance = alliance + corp.save() + else: + logger.info("Creating new alliance member corp id %s" % member_corp) + corpinfo = EveApiManager.get_corporation_information(member_corp) + EveManager.create_corporation_info(corpinfo['id'], corpinfo['name'], corpinfo['ticker'], + corpinfo['members']['current'], blue, alliance) + + +@task +def update_alliance(id): + alliance = EveAllianceInfo.objects.get(alliance_id=id) + corps = EveCorporationInfo.objects.filter(alliance=alliance) + logger.debug("Updating alliance %s with %s member corps" % (alliance, len(corps))) + allianceinfo = EveApiManager.get_alliance_information(alliance.alliance_id) + if allianceinfo: + EveManager.update_alliance_info(allianceinfo['id'], allianceinfo['executor_id'], + allianceinfo['member_count'], alliance.is_blue) + for corp in corps: + if corp.corporation_id in allianceinfo['member_corps'] is False: + logger.info("Corp %s no longer in alliance %s" % (corp, alliance)) + corp.alliance = None + corp.save() + populate_alliance(alliance.alliance_id, blue=alliance.is_blue) + elif EveApiManager.check_if_alliance_exists(alliance.alliance_id) is False: + logger.info("Alliance %s has closed. Deleting model" % alliance) + alliance.delete() + + +@task +def update_corp(id): + corp = EveCorporationInfo.objects.get(corporation_id=id) + logger.debug("Updating corp %s" % corp) + corpinfo = EveApiManager.get_corporation_information(corp.corporation_id) + if corpinfo: + alliance = None + if EveAllianceInfo.objects.filter(alliance_id=corpinfo['alliance']['id']).exists(): + alliance = EveAllianceInfo.objects.get(alliance_id=corpinfo['alliance']['id']) + EveManager.update_corporation_info(corpinfo['id'], corpinfo['members']['current'], alliance, corp.is_blue) + elif EveApiManager.check_if_corp_exists(corp.corporation_id) is False: + logger.info("Corp %s has closed. Deleting model" % corp) + corp.delete() + + # Run Every 2 hours + + +@periodic_task(run_every=crontab(minute=0, hour="*/2")) +def run_corp_update(): + if EveApiManager.check_if_api_server_online() is False: + logger.warn("Aborted updating corp and alliance models: API server unreachable") + return + standing_level = 'alliance' + try: + # get corp info for owning corp if required + ownercorpinfo = {} + if settings.IS_CORP: + standing_level = 'corp' + logger.debug("Getting information for owning corp with id %s" % settings.CORP_ID) + ownercorpinfo = EveApiManager.get_corporation_information(settings.CORP_ID) + if not ownercorpinfo: + logger.error("Failed to retrieve corp info for owning corp id %s - bad corp id?" % settings.CORP_ID) + return + + # check if we need to update an alliance model + alliance_id = '' + if ownercorpinfo and ownercorpinfo['alliance']['id']: + alliance_id = ownercorpinfo['alliance']['id'] + elif settings.IS_CORP is False: + alliance_id = settings.ALLIANCE_ID + + # get and create alliance info for owning alliance if required + alliance = None + if alliance_id: + logger.debug("Getting information for owning alliance with id %s" % alliance_id) + ownerallianceinfo = EveApiManager.get_alliance_information(alliance_id) + if not ownerallianceinfo: + logger.error("Failed to retrieve corp info for owning alliance id %s - bad alliance id?" % alliance_id) + return + if EveAllianceInfo.objects.filter(alliance_id=ownerallianceinfo['id']).exists(): + logger.debug("Updating existing owner alliance model with id %s" % alliance_id) + EveManager.update_alliance_info(ownerallianceinfo['id'], ownerallianceinfo['executor_id'], + ownerallianceinfo['member_count'], False) + else: + populate_alliance(alliance_id) + alliance = EveAllianceInfo.objects.get(alliance_id=alliance_id) + + # create corp info for owning corp if required + if ownercorpinfo: + if EveCorporationInfo.objects.filter(corporation_id=ownercorpinfo['id']).exists(): + logger.debug("Updating existing owner corp model with id %s" % ownercorpinfo['id']) + EveManager.update_corporation_info(ownercorpinfo['id'], ownercorpinfo['members']['current'], alliance, + False) + else: + logger.info("Creating model for owning corp with id %s" % ownercorpinfo['id']) + EveManager.create_corporation_info(ownercorpinfo['id'], ownercorpinfo['name'], ownercorpinfo['ticker'], + ownercorpinfo['members']['current'], False, alliance) + + # validate and create corp models for member corps of owning alliance + if alliance: + current_corps = EveCorporationInfo.objects.filter(alliance=alliance) + for corp in current_corps: + if corp.corporation_id in ownerallianceinfo['member_corps'] is False: + logger.info("Corp %s is no longer in owning alliance %s - updating model." % (corp, alliance)) + corp.alliance = None + corp.save() + for member_corp in ownerallianceinfo['member_corps']: + if EveCorporationInfo.objects.filter(corporation_id=member_corp).exists(): + corp = EveCorporationInfo.objects.get(corporation_id=member_corp) + if corp.alliance == alliance is not True: + logger.info("Associating corp %s with owning alliance %s" % (corp, alliance)) + corp.alliance = alliance + corp.save() + else: + corpinfo = EveApiManager.get_corporation_information(member_corp) + logger.info("Creating model for owning alliance member corp with id %s" % corpinfo['id']) + EveManager.create_corporation_info(corpinfo['id'], corpinfo['name'], corpinfo['ticker'], + corpinfo['members']['current'], False, alliance) + + # update existing corp models + for corp in EveCorporationInfo.objects.all(): + update_corp.delay(corp.corporation_id) + + # update existing alliance models + for alliance in EveAllianceInfo.objects.all(): + update_alliance.delay(alliance.alliance_id) + + # create standings + standings = EveApiManager.get_corp_standings() + if standings: + standings = standings[standing_level] + for standing in standings: + if int(standings[standing]['standing']) >= settings.BLUE_STANDING: + logger.debug("Standing %s meets threshold" % standing) + if EveApiManager.check_if_id_is_alliance(standing): + logger.debug("Standing %s is an alliance" % standing) + if EveAllianceInfo.objects.filter(alliance_id=standing).exists(): + alliance = EveAllianceInfo.objects.get(alliance_id=standing) + if alliance.is_blue is not True: + logger.info("Updating alliance %s as blue" % alliance) + alliance.is_blue = True + alliance.save() + else: + populate_alliance(standing, blue=True) + elif EveApiManager.check_if_id_is_corp(standing): + logger.debug("Standing %s is a corp" % standing) + if EveCorporationInfo.objects.filter(corporation_id=standing).exists(): + corp = EveCorporationInfo.objects.get(corporation_id=standing) + if corp.is_blue is not True: + logger.info("Updating corp %s as blue" % corp) + corp.is_blue = True + corp.save() + else: + logger.info("Creating model for blue corp with id %s" % standing) + corpinfo = EveApiManager.get_corporation_information(standing) + corp_alliance = None + if EveAllianceInfo.objects.filter(alliance_id=corpinfo['alliance']['id']).exists(): + logger.debug("New corp model for standing %s has existing alliance model" % standing) + corp_alliance = EveAllianceInfo.objects.get(alliance_id=corpinfo['alliance']['id']) + EveManager.create_corporation_info(corpinfo['id'], corpinfo['name'], corpinfo['ticker'], + corpinfo['members']['current'], True, corp_alliance) + + # update alliance standings + for alliance in EveAllianceInfo.objects.filter(is_blue=True): + if int(alliance.alliance_id) in standings: + if float(standings[int(alliance.alliance_id)]['standing']) < float(settings.BLUE_STANDING): + logger.info("Alliance %s no longer meets minimum blue standing threshold" % alliance) + alliance.is_blue = False + alliance.save() + else: + logger.info("Alliance %s no longer in standings" % alliance) + alliance.is_blue = False + alliance.save() + + # update corp standings + for corp in EveCorporationInfo.objects.filter(is_blue=True): + if int(corp.corporation_id) in standings: + if float(standings[int(corp.corporation_id)]['standing']) < float(settings.BLUE_STANDING): + logger.info("Corp %s no longer meets minimum blue standing threshold" % corp) + corp.is_blue = False + corp.save() + else: + if corp.alliance: + if not corp.alliance.is_blue: + logger.info("Corp %s and its alliance %s are no longer blue" % (corp, corp.alliance)) + corp.is_blue = False + corp.save() + else: + logger.info("Corp %s is no longer blue" % corp) + corp.is_blue = False + corp.save() + + # delete unnecessary alliance models + for alliance in EveAllianceInfo.objects.filter(is_blue=False): + logger.debug("Checking to delete alliance %s" % alliance) + if not settings.IS_CORP: + if not alliance.alliance_id == settings.ALLIANCE_ID: + logger.info("Deleting unnecessary alliance model %s" % alliance) + alliance.delete() + else: + if not alliance.evecorporationinfo_set.filter(corporation_id=settings.CORP_ID).exists(): + logger.info("Deleting unnecessary alliance model %s" % alliance) + alliance.delete() + + # delete unnecessary corp models + for corp in EveCorporationInfo.objects.filter(is_blue=False): + logger.debug("Checking to delete corp %s" % corp) + if not settings.IS_CORP: + if corp.alliance: + logger.debug("Corp %s has alliance %s" % (corp, corp.alliance)) + if not corp.alliance.alliance_id == settings.ALLIANCE_ID: + logger.info("Deleting unnecessary corp model %s" % corp) + corp.delete() + else: + logger.info("Deleting unnecessary corp model %s" % corp) + corp.delete() + else: + if corp.corporation_id != settings.CORP_ID: + logger.debug("Corp %s is not owning corp" % corp) + if corp.alliance: + logger.debug("Corp %s has alliance %s" % (corp, corp.alliance)) + if not corp.alliance.evecorporationinfo_set.filter(corporation_id=settings.CORP_ID).exists(): + logger.info("Deleting unnecessary corp model %s" % corp) + corp.delete() + else: + logger.info("Deleting unnecessary corp model %s" % corp) + corp.delete() + else: + logger.debug("Corp %s is owning corp" % corp) + except evelink.api.APIError as e: + logger.error("Model update failed with error code %s" % e.code) diff --git a/eveonline/views.py b/eveonline/views.py index 4b65ecb9..d224d3c1 100755 --- a/eveonline/views.py +++ b/eveonline/views.py @@ -1,59 +1,27 @@ -from django.conf import settings -from django.http import HttpResponseRedirect -from django.shortcuts import render_to_response -from django.template import RequestContext +from __future__ import unicode_literals +from django.shortcuts import render, redirect from django.contrib.auth.decorators import login_required -from django.contrib.auth.decorators import permission_required +from django.contrib import messages -from util import add_member_permission -from util import remove_member_permission -from util import check_if_user_has_permission -from forms import UpdateKeyForm -from managers import EveManager +from eveonline.forms import UpdateKeyForm +from eveonline.managers import EveManager from authentication.managers import AuthServicesInfoManager from services.managers.eve_api_manager import EveApiManager -from util.common_task import add_user_to_group -from util.common_task import remove_user_from_group -from util.common_task import deactivate_services -from util.common_task import generate_corp_group_name -from eveonline.models import EveCorporationInfo -from eveonline.models import EveCharacter from eveonline.models import EveApiKeyPair from authentication.models import AuthServicesInfo -from celerytask.tasks import determine_membership_by_user -from celerytask.tasks import set_state -from celerytask.tasks import refresh_api +from authentication.tasks import set_state +from eveonline.tasks import refresh_api import logging logger = logging.getLogger(__name__) -def disable_member(user, char_id): - logger.debug("Disabling user %s with character id %s" % (user, char_id)) - remove_member_permission(user, 'member') - remove_user_from_group(user, settings.DEFAULT_AUTH_GROUP) - remove_user_from_group(user, - generate_corp_group_name( - EveManager.get_character_by_id(char_id).corporation_name)) - deactivate_services(user) - logger.info("Disabled member %s" % user) - - -def disable_blue_member(user): - logger.debug("Disabling blue user %s" % user) - remove_member_permission(user, 'blue_member') - remove_user_from_group(user, settings.DEFAULT_BLUE_GROUP) - deactivate_services(user) - logger.info("Disabled blue user %s" % user) - @login_required def add_api_key(request): logger.debug("add_api_key called by user %s" % request.user) - user_state = determine_membership_by_user(request.user) if request.method == 'POST': - form = UpdateKeyForm(request.POST) - form.user_state=user_state + form = UpdateKeyForm(request.user, request.POST) logger.debug("Request type POST with form valid: %s" % form.is_valid()) if form.is_valid(): EveManager.create_api_keypair(form.cleaned_data['api_id'], @@ -65,16 +33,18 @@ def add_api_key(request): form.cleaned_data['api_key']) EveManager.create_characters_from_list(characters, request.user, form.cleaned_data['api_id']) logger.info("Successfully processed api add form for user %s" % request.user) - return HttpResponseRedirect("/api_key_management/") + messages.success(request, 'Added API key %s to your account.' % form.cleaned_data['api_id']) + auth = AuthServicesInfo.objects.get_or_create(user=request.user)[0] + if not auth.main_char_id: + messages.warning(request, 'Please select a main character.') + return redirect("/api_key_management/") else: logger.debug("Form invalid: returning to form.") else: logger.debug("Providing empty update key form for user %s" % request.user) - form = UpdateKeyForm() - form.user_state = user_state + form = UpdateKeyForm(request.user) context = {'form': form, 'apikeypairs': EveManager.get_api_key_pairs(request.user.id)} - return render_to_response('registered/addapikey.html', context, - context_instance=RequestContext(request)) + return render(request, 'registered/addapikey.html', context=context) @login_required @@ -82,51 +52,48 @@ def api_key_management_view(request): logger.debug("api_key_management_view called by user %s" % request.user) context = {'apikeypairs': EveManager.get_api_key_pairs(request.user.id)} - return render_to_response('registered/apikeymanagment.html', context, - context_instance=RequestContext(request)) + return render(request, 'registered/apikeymanagment.html', context=context) @login_required def api_key_removal(request, api_id): logger.debug("api_key_removal called by user %s for api id %s" % (request.user, api_id)) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] # Check if our users main id is in the to be deleted characters characters = EveManager.get_characters_by_owner_id(request.user.id) if characters is not None: for character in characters: if character.character_id == authinfo.main_char_id: if character.api_id == api_id: - # TODO: Remove services also - if authinfo.is_blue: - logger.debug("Blue user %s deleting api for main character. Disabling." % request.user) - disable_blue_member(request.user) - else: - logger.debug("User %s deleting api for main character. Disabling." % request.user) - disable_member(request.user, authinfo.main_char_id) + messages.warning(request, + 'You have deleted your main character. Please select a new main character.') + set_state(request.user) EveManager.delete_api_key_pair(api_id, request.user.id) EveManager.delete_characters_by_api_id(api_id, request.user.id) + messages.success(request, 'Deleted API key %s' % api_id) logger.info("Succesfully processed api delete request by user %s for api %s" % (request.user, api_id)) - return HttpResponseRedirect("/api_key_management/") + return redirect("auth_api_key_management") @login_required def characters_view(request): logger.debug("characters_view called by user %s" % request.user) render_items = {'characters': EveManager.get_characters_by_owner_id(request.user.id), - 'authinfo': AuthServicesInfoManager.get_auth_service_info(request.user)} - return render_to_response('registered/characters.html', render_items, context_instance=RequestContext(request)) + 'authinfo': AuthServicesInfo.objects.get_or_create(user=request.user)[0]} + return render(request, 'registered/characters.html', context=render_items) @login_required def main_character_change(request, char_id): logger.debug("main_character_change called by user %s for character id %s" % (request.user, char_id)) if EveManager.check_if_character_owned_by_user(char_id, request.user): - AuthServicesInfoManager.update_main_char_Id(char_id, request.user) + AuthServicesInfoManager.update_main_char_id(char_id, request.user) set_state(request.user) - return HttpResponseRedirect("/characters/") - return HttpResponseRedirect("/characters/") - + messages.success(request, 'Changed main character ID to %s' % char_id) + return redirect("auth_characters") + messages.error(request, 'Failed to change main character - selected character is not owned by your account.') + return redirect("auth_characters") @login_required @@ -136,9 +103,12 @@ def user_refresh_api(request, api_id): api_key_pair = EveApiKeyPair.objects.get(api_id=api_id) if api_key_pair.user == request.user: refresh_api(api_key_pair) + messages.success(request, 'Refreshed API key %s' % api_id) set_state(request.user) else: + messages.warning(request, 'You are not authorized to refresh that API key.') logger.warn("User %s not authorized to refresh api id %s" % (request.user, api_id)) else: + messages.warning(request, 'Unable to locate API key %s' % api_id) logger.warn("User %s unable to refresh api id %s - api key not found" % (request.user, api_id)) - return HttpResponseRedirect("/api_key_management/") + return redirect("auth_api_key_management") diff --git a/fleetactivitytracking/__init__.py b/fleetactivitytracking/__init__.py index e69de29b..baffc488 100644 --- a/fleetactivitytracking/__init__.py +++ b/fleetactivitytracking/__init__.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/fleetactivitytracking/admin.py b/fleetactivitytracking/admin.py index 19a3a4ce..b000d7f2 100644 --- a/fleetactivitytracking/admin.py +++ b/fleetactivitytracking/admin.py @@ -1,5 +1,6 @@ +from __future__ import unicode_literals from django.contrib import admin -from models import Fatlink, Fat +from fleetactivitytracking.models import Fatlink, Fat admin.site.register(Fatlink) diff --git a/fleetactivitytracking/apps.py b/fleetactivitytracking/apps.py new file mode 100644 index 00000000..219e0b38 --- /dev/null +++ b/fleetactivitytracking/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class FatConfig(AppConfig): + name = 'fleetactivitytracking' diff --git a/fleetactivitytracking/forms.py b/fleetactivitytracking/forms.py index 20dfc9c3..4d5c256d 100644 --- a/fleetactivitytracking/forms.py +++ b/fleetactivitytracking/forms.py @@ -1,7 +1,9 @@ +from __future__ import unicode_literals from django import forms from optimer.models import optimer from django.utils.translation import ugettext_lazy as _ + def get_fleet_list(): fleets = optimer.objects.all() fleetlist = [("None", "None")] @@ -13,5 +15,6 @@ def get_fleet_list(): class FatlinkForm(forms.Form): fatname = forms.CharField(label=_('Name of fat-link'), required=True) - duration = forms.IntegerField(label=_("Duration of fat-link"), required=True, initial=30, min_value=1, max_value=2147483647) - fleet = forms.ModelChoiceField(label=_("Fleet"), queryset=optimer.objects.all().order_by('operation_name')) \ No newline at end of file + duration = forms.IntegerField(label=_("Duration of fat-link"), required=True, initial=30, min_value=1, + max_value=2147483647) + fleet = forms.ModelChoiceField(label=_("Fleet"), queryset=optimer.objects.all().order_by('operation_name')) diff --git a/fleetactivitytracking/migrations/0001_initial.py b/fleetactivitytracking/migrations/0001_initial.py new file mode 100644 index 00000000..75671c1a --- /dev/null +++ b/fleetactivitytracking/migrations/0001_initial.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-05 21:39 +from __future__ import unicode_literals + +import datetime +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +from django.utils.timezone import utc +import fleetactivitytracking.models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('eveonline', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Fat', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('system', models.CharField(max_length=30)), + ('shiptype', models.CharField(max_length=30)), + ('station', models.CharField(max_length=125)), + ('character', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eveonline.EveCharacter')), + ], + ), + migrations.CreateModel( + name='Fatlink', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('fatdatetime', models.DateTimeField(default=datetime.datetime(2016, 9, 5, 21, 39, 17, 307954, tzinfo=utc))), + ('duration', models.PositiveIntegerField()), + ('fleet', models.CharField(default=b'', max_length=254)), + ('name', models.CharField(max_length=254)), + ('hash', models.CharField(max_length=254, unique=True)), + ('creator', models.ForeignKey(on_delete=models.SET(fleetactivitytracking.models.get_sentinel_user), to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.AddField( + model_name='fat', + name='fatlink', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='fleetactivitytracking.Fatlink'), + ), + migrations.AddField( + model_name='fat', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AlterUniqueTogether( + name='fat', + unique_together=set([('character', 'fatlink')]), + ), + ] diff --git a/fleetactivitytracking/migrations/0002_auto_20160905_2220.py b/fleetactivitytracking/migrations/0002_auto_20160905_2220.py new file mode 100644 index 00000000..8036c208 --- /dev/null +++ b/fleetactivitytracking/migrations/0002_auto_20160905_2220.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-05 22:20 +from __future__ import unicode_literals + +import datetime +from django.db import migrations, models +from django.utils.timezone import utc + + +class Migration(migrations.Migration): + + dependencies = [ + ('fleetactivitytracking', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='fatlink', + name='fatdatetime', + field=models.DateTimeField(default=datetime.datetime(2016, 9, 5, 22, 20, 2, 999041, tzinfo=utc)), + ), + ] diff --git a/fleetactivitytracking/migrations/0003_auto_20160906_2354.py b/fleetactivitytracking/migrations/0003_auto_20160906_2354.py new file mode 100644 index 00000000..63e30401 --- /dev/null +++ b/fleetactivitytracking/migrations/0003_auto_20160906_2354.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-06 23:54 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('fleetactivitytracking', '0002_auto_20160905_2220'), + ] + + operations = [ + migrations.AlterField( + model_name='fatlink', + name='fatdatetime', + field=models.DateTimeField(default=django.utils.timezone.now), + ), + ] diff --git a/sigtracker/__init__.py b/fleetactivitytracking/migrations/__init__.py similarity index 100% rename from sigtracker/__init__.py rename to fleetactivitytracking/migrations/__init__.py diff --git a/fleetactivitytracking/models.py b/fleetactivitytracking/models.py index d10806a1..acd4c50c 100644 --- a/fleetactivitytracking/models.py +++ b/fleetactivitytracking/models.py @@ -1,16 +1,18 @@ +from __future__ import unicode_literals +from django.utils.encoding import python_2_unicode_compatible from django.db import models from django.contrib.auth.models import User -from optimer.models import optimer from eveonline.models import EveCharacter -from datetime import datetime -from datetime import date from django.utils import timezone + def get_sentinel_user(): return User.objects.get_or_create(username='deleted')[0] + +@python_2_unicode_compatible class Fatlink(models.Model): - fatdatetime = models.DateTimeField(default=timezone.now()) + fatdatetime = models.DateTimeField(default=timezone.now) duration = models.PositiveIntegerField() fleet = models.CharField(max_length=254, default="") name = models.CharField(max_length=254) @@ -21,6 +23,7 @@ class Fatlink(models.Model): return self.name +@python_2_unicode_compatible class Fat(models.Model): character = models.ForeignKey(EveCharacter, on_delete=models.CASCADE) fatlink = models.ForeignKey(Fatlink) diff --git a/fleetactivitytracking/views.py b/fleetactivitytracking/views.py index 919c45f8..467efb84 100644 --- a/fleetactivitytracking/views.py +++ b/fleetactivitytracking/views.py @@ -1,19 +1,17 @@ +from __future__ import unicode_literals from django.conf import settings -from django.shortcuts import HttpResponseRedirect -from django.shortcuts import render_to_response +from django.shortcuts import render, redirect from django.core.exceptions import ObjectDoesNotExist from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import permission_required -from django.template import RequestContext from django.core.exceptions import ValidationError from django.utils import timezone from eveonline.models import EveCharacter from eveonline.models import EveCorporationInfo from eveonline.managers import EveManager -from util import check_if_user_has_permission -from forms import FatlinkForm -from models import Fatlink, Fat +from fleetactivitytracking.forms import FatlinkForm +from fleetactivitytracking.models import Fatlink, Fat from slugify import slugify @@ -23,7 +21,6 @@ import string import random import datetime - import logging logger = logging.getLogger(__name__) @@ -34,24 +31,26 @@ class CorpStat(object): if corp: self.corp = corp else: - self.corp = EveCorporationInfo.objects.get(corporation_id=corp_id) + self.corp = EveCorporationInfo.objects.get(corporation_id=corp_id) self.n_fats = 0 self.blue = blue def avg_fat(self): - return "%.2f" % (float(self.n_fats)/float(self.corp.member_count)) + return "%.2f" % (float(self.n_fats) / float(self.corp.member_count)) + def first_day_of_next_month(year, month): if month == 12: - return datetime.datetime(year+1,1,1) + return datetime.datetime(year + 1, 1, 1) else: - return datetime.datetime(year, month+1, 1) + return datetime.datetime(year, month + 1, 1) + def first_day_of_previous_month(year, month): if month == 1: - return datetime.datetime(year-1,12,1) + return datetime.datetime(year - 1, 12, 1) else: - return datetime.datetime(year, month-1, 1) + return datetime.datetime(year, month - 1, 1) @login_required @@ -63,14 +62,14 @@ def fatlink_view(request): logger.debug("fatlink_view called by user %s" % request.user) latest_fats = Fat.objects.filter(user=user).order_by('-id')[:5] - if check_if_user_has_permission(user, 'fleetactivitytracking'): + if user.has_perm('auth.fleetactivitytracking'): latest_links = Fatlink.objects.all().order_by('-id')[:5] - context = {'user':user, 'fats': latest_fats, 'fatlinks': latest_links} + context = {'user': user, 'fats': latest_fats, 'fatlinks': latest_links} else: - context = {'user':user, 'fats': latest_fats} + context = {'user': user, 'fats': latest_fats} - return render_to_response('registered/fatlinkview.html', context, context_instance=RequestContext(request)) + return render(request, 'registered/fatlinkview.html', context=context) @login_required @@ -91,7 +90,8 @@ def fatlink_statistics_view(request, year=datetime.date.today().year, month=date for corp in alliance_corps: fatStats[corp.corporation_name] = CorpStat(corp.corporation_id, corp=corp) - fatlinks_in_span = Fatlink.objects.filter(fatdatetime__gte = start_of_month).filter(fatdatetime__lt = start_of_next_month) + fatlinks_in_span = Fatlink.objects.filter(fatdatetime__gte=start_of_month).filter( + fatdatetime__lt=start_of_next_month) for fatlink in fatlinks_in_span: fats_in_fatlink = Fat.objects.filter(fatlink=fatlink) @@ -102,15 +102,16 @@ def fatlink_statistics_view(request, year=datetime.date.today().year, month=date fatStatsList = [fatStat for corp_name, fatStat in fatStats.items()] fatStatsList.sort(key=lambda stat: stat.corp.corporation_name) - fatStatsList.sort(key=lambda stat: (stat.n_fats, stat.n_fats/stat.corp.member_count), reverse=True) + fatStatsList.sort(key=lambda stat: (stat.n_fats, stat.n_fats / stat.corp.member_count), reverse=True) if datetime.datetime.now() > start_of_next_month: - context = {'fatStats':fatStatsList, 'month':start_of_month.strftime("%B"), 'year':year, 'previous_month': start_of_previous_month,'next_month': start_of_next_month} + context = {'fatStats': fatStatsList, 'month': start_of_month.strftime("%B"), 'year': year, + 'previous_month': start_of_previous_month, 'next_month': start_of_next_month} else: - context = {'fatStats':fatStatsList, 'month':start_of_month.strftime("%B"), 'year':year, 'previous_month': start_of_previous_month} - - return render_to_response('registered/fatlinkstatisticsview.html', context, context_instance=RequestContext(request)) + context = {'fatStats': fatStatsList, 'month': start_of_month.strftime("%B"), 'year': year, + 'previous_month': start_of_previous_month} + return render(request, 'registered/fatlinkstatisticsview.html', context=context) @login_required @@ -123,21 +124,22 @@ def fatlink_personal_statistics_view(request, year=datetime.date.today().year, m personal_fats = Fat.objects.filter(user=user).order_by('id') - monthlystats = [0 for month in range(1,13)] + monthlystats = [0 for month in range(1, 13)] for fat in personal_fats: fatdate = fat.fatlink.fatdatetime if fatdate.year == year: - monthlystats[fatdate.month-1] += 1 + monthlystats[fatdate.month - 1] += 1 - monthlystats = [(i+1, datetime.date(year, i+1, 1).strftime("%h"), monthlystats[i]) for i in range(12)] + monthlystats = [(i + 1, datetime.date(year, i + 1, 1).strftime("%h"), monthlystats[i]) for i in range(12)] - if datetime.datetime.now() > datetime.datetime(year+1, 1, 1): - context = {'user':user, 'monthlystats': monthlystats, 'year':year, 'previous_year':year-1, 'next_year':year+1} + if datetime.datetime.now() > datetime.datetime(year + 1, 1, 1): + context = {'user': user, 'monthlystats': monthlystats, 'year': year, 'previous_year': year - 1, + 'next_year': year + 1} else: - context = {'user':user, 'monthlystats': monthlystats, 'year':year, 'previous_year':year-1} + context = {'user': user, 'monthlystats': monthlystats, 'year': year, 'previous_year': year - 1} - return render_to_response('registered/fatlinkpersonalstatisticsview.html', context, context_instance=RequestContext(request)) + return render(request, 'registered/fatlinkpersonalstatisticsview.html', context=context) @login_required @@ -148,28 +150,30 @@ def fatlink_monthly_personal_statistics_view(request, year, month, char_id=None) start_of_next_month = first_day_of_next_month(year, month) start_of_previous_month = first_day_of_previous_month(year, month) - if check_if_user_has_permission(request.user, 'fleetactivitytracking_statistics') and char_id: + if request.user.has_perm('auth.fleetactivitytracking_statistics') and char_id: user = EveCharacter.objects.get(character_id=char_id).user else: user = request.user logger.debug("Personal monthly statistics view for user %s called by %s" % (user, request.user)) - personal_fats = Fat.objects.filter(user=user).filter(fatlink__fatdatetime__gte = start_of_month).filter(fatlink__fatdatetime__lt = start_of_next_month) + personal_fats = Fat.objects.filter(user=user).filter(fatlink__fatdatetime__gte=start_of_month).filter( + fatlink__fatdatetime__lt=start_of_next_month) ship_statistics = dict() n_fats = 0 for fat in personal_fats: ship_statistics[fat.shiptype] = ship_statistics.setdefault(fat.shiptype, 0) + 1 n_fats += 1 - context = {'user': user, 'shipStats':sorted(ship_statistics.items()), 'month':start_of_month.strftime("%h"), - 'year':year, 'n_fats': n_fats, 'char_id': char_id, 'previous_month': start_of_previous_month, + context = {'user': user, 'shipStats': sorted(ship_statistics.items()), 'month': start_of_month.strftime("%h"), + 'year': year, 'n_fats': n_fats, 'char_id': char_id, 'previous_month': start_of_previous_month, 'next_month': start_of_next_month} - created_fats = Fatlink.objects.filter(creator=user).filter(fatdatetime__gte = start_of_month).filter(fatdatetime__lt = start_of_next_month) + created_fats = Fatlink.objects.filter(creator=user).filter(fatdatetime__gte=start_of_month).filter( + fatdatetime__lt=start_of_next_month) context["created_fats"] = created_fats context["n_created_fats"] = len(created_fats) - return render_to_response('registered/fatlinkpersonalmonthlystatisticsview.html', context, context_instance=RequestContext(request)) + return render(request, 'registered/fatlinkpersonalmonthlystatisticsview.html', context=context) @login_required @@ -182,10 +186,8 @@ def click_fatlink_view(request, hash, fatname): # Retrieve the latest fatlink using the hash. try: fatlink = Fatlink.objects.filter(hash=hash)[0] - valid = True - if (timezone.now() - fatlink.fatdatetime) < datetime.timedelta(seconds=(fatlink.duration*60)): - active = True + if (timezone.now() - fatlink.fatdatetime) < datetime.timedelta(seconds=(fatlink.duration * 60)): character = EveManager.get_character_by_id(request.META['HTTP_EVE_CHARID']) @@ -210,15 +212,16 @@ def click_fatlink_view(request, hash, fatname): messages.append(message[0].decode()) context = {'trusted': True, 'errormessages': messages} else: - context = {'character_id': request.META['HTTP_EVE_CHARID'], 'character_name': request.META['HTTP_EVE_CHARNAME']} - return render_to_response('public/characternotexisting.html', context, context_instance=RequestContext(request)) + context = {'character_id': request.META['HTTP_EVE_CHARID'], + 'character_name': request.META['HTTP_EVE_CHARNAME']} + return render(request, 'public/characternotexisting.html', context=context) else: context = {'trusted': True, 'expired': True} except ObjectDoesNotExist: context = {'trusted': True} else: context = {'trusted': False, 'fatname': fatname} - return render_to_response('public/clickfatlinkview.html', context, context_instance=RequestContext(request)) + return render(request, 'public/clickfatlinkview.html', context=context) @login_required @@ -237,7 +240,7 @@ def create_fatlink_view(request): fatlink.duration = form.cleaned_data["duration"] fatlink.fatdatetime = timezone.now() fatlink.creator = request.user - fatlink.hash = ''.join(random.choice(string.ascii_letters+string.digits) for i in range(10)) + fatlink.hash = ''.join(random.choice(string.ascii_letters + string.digits) for i in range(10)) try: fatlink.full_clean() fatlink.save() @@ -247,12 +250,12 @@ def create_fatlink_view(request): for errorname, message in e.message_dict.items(): messages.append(message[0].decode()) context = {'form': form, 'errormessages': messages} - return render_to_response('registered/fatlinkformatter.html', context, context_instance=RequestContext(request)) + return render(request, 'registered/fatlinkformatter.html', context=context) else: form = FatlinkForm() context = {'form': form, 'badrequest': True} - return render_to_response('registered/fatlinkformatter.html', context, context_instance=RequestContext(request)) - return HttpResponseRedirect('/fat/') + return render(request, 'registered/fatlinkformatter.html', context=context) + return redirect('auth_fatlink_view') else: form = FatlinkForm() @@ -260,7 +263,7 @@ def create_fatlink_view(request): context = {'form': form} - return render_to_response('registered/fatlinkformatter.html', context, context_instance=RequestContext(request)) + return render(request, 'registered/fatlinkformatter.html', context=context) @login_required @@ -268,25 +271,24 @@ def create_fatlink_view(request): def modify_fatlink_view(request, hash=""): logger.debug("modify_fatlink_view called by user %s" % request.user) if not hash: - return HttpResponseRedirect('/fat/') + return redirect('/fat/') fatlink = Fatlink.objects.filter(hash=hash)[0] - if(request.GET.get('removechar')): + if request.GET.get('removechar'): character_id = request.GET.get('removechar') character = EveCharacter.objects.get(character_id=character_id) - logger.debug("Removing character %s from fleetactivitytracking %s" % (character.character_name ,fatlink.name)) + logger.debug("Removing character %s from fleetactivitytracking %s" % (character.character_name, fatlink.name)) Fat.objects.filter(fatlink=fatlink).filter(character=character).delete() - if(request.GET.get('deletefat')): + if request.GET.get('deletefat'): logger.debug("Removing fleetactivitytracking %s" % fatlink.name) fatlink.delete() - return HttpResponseRedirect('/fat/') + return redirect('/fat/') registered_fats = Fat.objects.filter(fatlink=fatlink).order_by('character') - context = {'fatlink':fatlink, 'registered_fats':registered_fats} - - return render_to_response('registered/fatlinkmodify.html', context, context_instance=RequestContext(request)) + context = {'fatlink': fatlink, 'registered_fats': registered_fats} + return render(request, 'registered/fatlinkmodify.html', context=context) diff --git a/fleetup/__init__.py b/fleetup/__init__.py index e69de29b..baffc488 100755 --- a/fleetup/__init__.py +++ b/fleetup/__init__.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/fleetup/admin.py b/fleetup/admin.py index e69de29b..baffc488 100755 --- a/fleetup/admin.py +++ b/fleetup/admin.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/fleetup/apps.py b/fleetup/apps.py new file mode 100644 index 00000000..e8b5a203 --- /dev/null +++ b/fleetup/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class FleetupConfig(AppConfig): + name = 'fleetup' diff --git a/fleetup/forms.py b/fleetup/forms.py index e69de29b..baffc488 100755 --- a/fleetup/forms.py +++ b/fleetup/forms.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/fleetup/models.py b/fleetup/models.py index e69de29b..baffc488 100755 --- a/fleetup/models.py +++ b/fleetup/models.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/fleetup/views.py b/fleetup/views.py index 8c2bc0a8..b92fe451 100755 --- a/fleetup/views.py +++ b/fleetup/views.py @@ -1,42 +1,24 @@ +from __future__ import unicode_literals import datetime -from operator import itemgetter, attrgetter, methodcaller - -from django.utils.timezone import utc - -from django.conf import settings -from django.shortcuts import render_to_response -from django.template import RequestContext +from django.shortcuts import render from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import permission_required -from django.contrib.auth.decorators import user_passes_test -from django.shortcuts import HttpResponseRedirect from django.template.defaulttags import register -from django.contrib.humanize.templatetags.humanize import intword - -from collections import namedtuple - -from authentication.managers import AuthServicesInfoManager -from util import check_if_user_has_permission -from services.managers.eve_api_manager import EveApiManager from services.managers.fleetup_manager import FleetUpManager -from eveonline.models import EveCorporationInfo -from eveonline.models import EveAllianceInfo -from eveonline.models import EveCharacter -from authentication.models import AuthServicesInfo +from authentication.decorators import members_and_blues import logging logger = logging.getLogger(__name__) + @register.filter def get_item(dictionary, key): return dictionary.get(key) -def fleetup_util_test(user): - return check_if_user_has_permission(user, 'member') or check_if_user_has_permission(user, 'blue_member') @login_required -@user_passes_test(fleetup_util_test) +@members_and_blues() def fleetup_view(request): logger.debug("fleetup_view called by user %s" % request.user) @@ -48,7 +30,8 @@ def fleetup_view(request): "operations_list": sorted(operations_list.items()), "now": now} - return render_to_response('registered/fleetup.html',context, context_instance=RequestContext(request) ) + return render(request, 'registered/fleetup.html', context=context) + @login_required @permission_required('auth.human_resources') @@ -59,18 +42,20 @@ def fleetup_characters(request): context = {"member_list": sorted(member_list.items())} - return render_to_response('registered/fleetupcharacters.html',context, context_instance=RequestContext(request) ) + return render(request, 'registered/fleetupcharacters.html', context=context) + @login_required -@user_passes_test(fleetup_util_test) +@members_and_blues() def fleetup_fittings(request): logger.debug("fleetup_fittings called by user %s" % request.user) fitting_list = FleetUpManager.get_fleetup_fittings() context = {"fitting_list": sorted(fitting_list.items())} - return render_to_response('registered/fleetupfittingsview.html',context, context_instance=RequestContext(request) ) + return render(request, 'registered/fleetupfittingsview.html', context=context) + @login_required -@user_passes_test(fleetup_util_test) +@members_and_blues() def fleetup_fitting(request, fittingnumber): logger.debug("fleetup_fitting called by user %s" % request.user) fitting_eft = FleetUpManager.get_fleetup_fitting_eft(fittingnumber) @@ -80,22 +65,22 @@ def fleetup_fitting(request, fittingnumber): context = {"fitting_eft": fitting_eft, "fitting_data": fitting_data, "doctrines_list": doctrines_list} - return render_to_response('registered/fleetupfitting.html',context, context_instance=RequestContext(request) ) + return render(request, 'registered/fleetupfitting.html', context=context) @login_required -@user_passes_test(fleetup_util_test) +@members_and_blues() def fleetup_doctrines(request): logger.debug("fleetup_doctrines called by user %s" % request.user) doctrines_list = FleetUpManager.get_fleetup_doctrines() context = {"doctrines_list": doctrines_list} - return render_to_response('registered/fleetupdoctrinesview.html',context, context_instance=RequestContext(request) ) + return render(request, 'registered/fleetupdoctrinesview.html', context=context) + @login_required -@user_passes_test(fleetup_util_test) +@members_and_blues() def fleetup_doctrine(request, doctrinenumber): logger.debug("fleetup_doctrine called by user %s" % request.user) doctrine = FleetUpManager.get_fleetup_doctrine(doctrinenumber) context = {"doctrine": doctrine} - return render_to_response('registered/fleetupdoctrine.html',context, context_instance=RequestContext(request) ) - + return render(request, 'registered/fleetupdoctrine.html', context=context) diff --git a/groupmanagement/__init__.py b/groupmanagement/__init__.py index e69de29b..baffc488 100644 --- a/groupmanagement/__init__.py +++ b/groupmanagement/__init__.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/groupmanagement/admin.py b/groupmanagement/admin.py index 27e1ae99..4d21a00f 100644 --- a/groupmanagement/admin.py +++ b/groupmanagement/admin.py @@ -1,9 +1,10 @@ +from __future__ import unicode_literals from django.contrib import admin -from models import GroupDescription -from models import GroupRequest -from models import HiddenGroup -from models import OpenGroup +from groupmanagement.models import GroupDescription +from groupmanagement.models import GroupRequest +from groupmanagement.models import HiddenGroup +from groupmanagement.models import OpenGroup admin.site.register(GroupDescription) diff --git a/groupmanagement/apps.py b/groupmanagement/apps.py new file mode 100644 index 00000000..74482d3d --- /dev/null +++ b/groupmanagement/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class GroupManagementConfig(AppConfig): + name = 'groupmanagement' diff --git a/groupmanagement/migrations/0001_initial.py b/groupmanagement/migrations/0001_initial.py new file mode 100644 index 00000000..60298099 --- /dev/null +++ b/groupmanagement/migrations/0001_initial.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-05 21:39 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0008_alter_user_username_max_length'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('eveonline', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='GroupDescription', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('description', models.CharField(max_length=512)), + ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.Group', unique=True)), + ], + ), + migrations.CreateModel( + name='GroupRequest', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('status', models.CharField(max_length=254)), + ('leave_request', models.BooleanField(default=0)), + ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.Group')), + ('main_char', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eveonline.EveCharacter')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='HiddenGroup', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.Group', unique=True)), + ], + ), + migrations.CreateModel( + name='OpenGroup', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('group', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='auth.Group')), + ], + ), + ] diff --git a/groupmanagement/migrations/0002_auto_20160906_2354.py b/groupmanagement/migrations/0002_auto_20160906_2354.py new file mode 100644 index 00000000..4b8db963 --- /dev/null +++ b/groupmanagement/migrations/0002_auto_20160906_2354.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-06 23:54 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('groupmanagement', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='groupdescription', + name='group', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='auth.Group'), + ), + migrations.AlterField( + model_name='hiddengroup', + name='group', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='auth.Group'), + ), + ] diff --git a/groupmanagement/migrations/0003_default_groups.py b/groupmanagement/migrations/0003_default_groups.py new file mode 100644 index 00000000..c2af1db1 --- /dev/null +++ b/groupmanagement/migrations/0003_default_groups.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-09 23:22 +from __future__ import unicode_literals + +from django.db import migrations +from django.conf import settings + +def create_groups(apps, schema_editor): + Group = apps.get_model('auth', 'Group') + Group.objects.get_or_create(name=settings.DEFAULT_AUTH_GROUP) + Group.objects.get_or_create(name=settings.DEFAULT_BLUE_GROUP) + +def reverse(apps, schema_editor): + pass + +class Migration(migrations.Migration): + + dependencies = [ + ('groupmanagement', '0002_auto_20160906_2354'), + ] + + operations = [ + migrations.RunPython(create_groups, reverse) + ] diff --git a/groupmanagement/migrations/__init__.py b/groupmanagement/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/groupmanagement/models.py b/groupmanagement/models.py index 93776a48..ffad61aa 100644 --- a/groupmanagement/models.py +++ b/groupmanagement/models.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals +from django.utils.encoding import python_2_unicode_compatible from django.db import models from django.contrib.auth.models import User from django.contrib.auth.models import Group @@ -5,14 +7,16 @@ from django.contrib.auth.models import Group from eveonline.models import EveCharacter +@python_2_unicode_compatible class GroupDescription(models.Model): description = models.CharField(max_length=512) - group = models.ForeignKey(Group, unique=True) + group = models.OneToOneField(Group) def __str__(self): return self.group.name + " - Description" +@python_2_unicode_compatible class GroupRequest(models.Model): status = models.CharField(max_length=254) leave_request = models.BooleanField(default=0) @@ -23,12 +27,16 @@ class GroupRequest(models.Model): def __str__(self): return self.user.username + ":" + self.group.name + +@python_2_unicode_compatible class HiddenGroup(models.Model): - group = models.ForeignKey(Group, unique=True) + group = models.OneToOneField(Group) def __str__(self): return self.group.name + " - Hidden" + +@python_2_unicode_compatible class OpenGroup(models.Model): group = models.OneToOneField(Group) diff --git a/groupmanagement/views.py b/groupmanagement/views.py index 214e9530..9a9eaf91 100755 --- a/groupmanagement/views.py +++ b/groupmanagement/views.py @@ -1,16 +1,16 @@ -from django.template import RequestContext -from django.shortcuts import HttpResponseRedirect -from django.shortcuts import render_to_response +from __future__ import unicode_literals +from django.shortcuts import render, redirect from django.conf import settings from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import permission_required from django.contrib.auth.models import Group +from django.contrib import messages from notifications import notify -from models import GroupDescription -from models import GroupRequest -from models import HiddenGroup -from models import OpenGroup -from authentication.managers import AuthServicesInfoManager +from groupmanagement.models import GroupDescription +from groupmanagement.models import GroupRequest +from groupmanagement.models import HiddenGroup +from groupmanagement.models import OpenGroup +from authentication.models import AuthServicesInfo from eveonline.managers import EveManager from django.utils.translation import ugettext_lazy as _ @@ -18,6 +18,7 @@ import logging logger = logging.getLogger(__name__) + @login_required @permission_required('auth.group_management') def group_management(request): @@ -30,12 +31,12 @@ def group_management(request): leaverequests.append(grouprequest) else: acceptrequests.append(grouprequest) - logger.debug("Providing user %s with %s acceptrequests and %s leaverequests." % (request.user, len(acceptrequests), len(leaverequests))) + logger.debug("Providing user %s with %s acceptrequests and %s leaverequests." % ( + request.user, len(acceptrequests), len(leaverequests))) render_items = {'acceptrequests': acceptrequests, 'leaverequests': leaverequests} - return render_to_response('registered/groupmanagement.html', - render_items, context_instance=RequestContext(request)) + return render(request, 'registered/groupmanagement.html', context=render_items) @login_required @@ -48,13 +49,20 @@ def group_accept_request(request, group_request_id): group_request.user.groups.add(group) group_request.user.save() group_request.delete() - logger.info("User %s accepted group request from user %s to group %s" % (request.user, group_request.user, group_request.group.name)) - notify(group_request.user, "Group Application Accepted", level="success", message="Your application to %s has been accepted." % group_request.group) + logger.info("User %s accepted group request from user %s to group %s" % ( + request.user, group_request.user, group_request.group.name)) + notify(group_request.user, "Group Application Accepted", level="success", + message="Your application to %s has been accepted." % group_request.group) + messages.success(request, + 'Accepted application from %s to %s.' % (group_request.main_char, group_request.group)) except: - logger.exception("Unhandled exception occured while user %s attempting to accept grouprequest id %s." % (request.user, group_request_id)) + messages.error(request, 'An unhandled error occurred while processing the application from %s to %s.' % ( + group_request.main_char, group_request.group)) + logger.exception("Unhandled exception occurred while user %s attempting to accept grouprequest id %s." % ( + request.user, group_request_id)) pass - return HttpResponseRedirect("/group/management/") + return redirect("auth_group_management") @login_required @@ -65,51 +73,74 @@ def group_reject_request(request, group_request_id): group_request = GroupRequest.objects.get(id=group_request_id) if group_request: - logger.info("User %s rejected group request from user %s to group %s" % (request.user, group_request.user, group_request.group.name)) + logger.info("User %s rejected group request from user %s to group %s" % ( + request.user, group_request.user, group_request.group.name)) group_request.delete() - notify(group_request.user, "Group Application Rejected", level="danger", message="Your application to %s has been rejected." % group_request.group) + notify(group_request.user, "Group Application Rejected", level="danger", + message="Your application to %s has been rejected." % group_request.group) + messages.success(request, + 'Rejected application from %s to %s.' % (group_request.main_char, group_request.group)) except: - logger.exception("Unhandled exception occured while user %s attempting to reject group request id %s" % (request.user, group_request_id)) + messages.error(request, 'An unhandled error occured while processing the application from %s to %s.' % ( + group_request.main_char, group_request.group)) + logger.exception("Unhandled exception occured while user %s attempting to reject group request id %s" % ( + request.user, group_request_id)) pass - return HttpResponseRedirect("/group/management/") + return redirect("auth_group_management") @login_required @permission_required('auth.group_management') def group_leave_accept_request(request, group_request_id): - logger.debug("group_leave_accept_request called by user %s for group request id %s" % (request.user, group_request_id)) + logger.debug( + "group_leave_accept_request called by user %s for group request id %s" % (request.user, group_request_id)) try: group_request = GroupRequest.objects.get(id=group_request_id) group, created = Group.objects.get_or_create(name=group_request.group.name) group_request.user.groups.remove(group) group_request.user.save() group_request.delete() - logger.info("User %s accepted group leave request from user %s to group %s" % (request.user, group_request.user, group_request.group.name)) - notify(group_request.user, "Group Leave Request Accepted", level="success", message="Your request to leave %s has been accepted." % group_request.group) + logger.info("User %s accepted group leave request from user %s to group %s" % ( + request.user, group_request.user, group_request.group.name)) + notify(group_request.user, "Group Leave Request Accepted", level="success", + message="Your request to leave %s has been accepted." % group_request.group) + messages.success(request, + 'Accepted application from %s to leave %s.' % (group_request.main_char, group_request.group)) except: - logger.exception("Unhandled exception occured while user %s attempting to accept group leave request id %s" % (request.user, group_request_id)) + messages.error(request, 'An unhandled error occured while processing the application from %s to leave %s.' % ( + group_request.main_char, group_request.group)) + logger.exception("Unhandled exception occured while user %s attempting to accept group leave request id %s" % ( + request.user, group_request_id)) pass - return HttpResponseRedirect("/group/management/") + return redirect("auth_group_management") @login_required @permission_required('auth.group_management') def group_leave_reject_request(request, group_request_id): - logger.debug("group_leave_reject_request called by user %s for group request id %s" % (request.user, group_request_id)) + logger.debug( + "group_leave_reject_request called by user %s for group request id %s" % (request.user, group_request_id)) try: group_request = GroupRequest.objects.get(id=group_request_id) if group_request: group_request.delete() - logger.info("User %s rejected group leave request from user %s for group %s" % (request.user, group_request.user, group_request.group.name)) - notify(group_request.user, "Group Leave Request Rejected", level="danger", message="Your request to leave %s has been rejected." % group_request.group) + logger.info("User %s rejected group leave request from user %s for group %s" % ( + request.user, group_request.user, group_request.group.name)) + notify(group_request.user, "Group Leave Request Rejected", level="danger", + message="Your request to leave %s has been rejected." % group_request.group) + messages.success(request, 'Rejected application from %s to leave %s.' % ( + group_request.main_char, group_request.group)) except: - logger.exception("Unhandled exception occured while user %s attempting to reject group leave request id %s" % (request.user, group_request_id)) + messages.error(request, 'An unhandled error occured while processing the application from %s to leave %s.' % ( + group_request.main_char, group_request.group)) + logger.exception("Unhandled exception occured while user %s attempting to reject group leave request id %s" % ( + request.user, group_request_id)) pass - return HttpResponseRedirect("/group/management/") + return redirect("auth_group_management") @login_required @@ -131,23 +162,22 @@ def groups_view(request): pass else: # Get the descriptionn - groupDesc = GroupDescription.objects.filter(group=group) - groupRequest = GroupRequest.objects.filter(user=request.user).filter(group=group) + group_desc = GroupDescription.objects.filter(group=group) + group_request = GroupRequest.objects.filter(user=request.user).filter(group=group) - if groupDesc: - if groupRequest: - paired_list.append((group, groupDesc[0], groupRequest[0])) + if group_desc: + if group_request: + paired_list.append((group, group_desc[0], group_request[0])) else: - paired_list.append((group, groupDesc[0], "")) + paired_list.append((group, group_desc[0], "")) else: - if groupRequest: - paired_list.append((group, "", groupRequest[0])) + if group_request: + paired_list.append((group, "", group_request[0])) else: paired_list.append((group, "", "")) render_items = {'pairs': paired_list} - return render_to_response('registered/groups.html', - render_items, context_instance=RequestContext(request)) + return render(request, 'registered/groups.html', context=render_items) @login_required @@ -157,8 +187,8 @@ def group_request_add(request, group_id): if OpenGroup.objects.filter(group=group).exists(): logger.info("%s joining %s as is an open group" % (request.user, group)) request.user.groups.add(group) - return HttpResponseRedirect("/groups") - auth_info = AuthServicesInfoManager.get_auth_service_info(request.user) + return redirect("auth_groups") + auth_info = AuthServicesInfo.objects.get_or_create(user=request.user)[0] grouprequest = GroupRequest() grouprequest.status = _('Pending') grouprequest.group = group @@ -167,7 +197,8 @@ def group_request_add(request, group_id): grouprequest.leave_request = False grouprequest.save() logger.info("Created group request for user %s to group %s" % (request.user, Group.objects.get(id=group_id))) - return HttpResponseRedirect("/groups") + messages.success(request, 'Applied to group %s.' % group) + return redirect("auth_groups") @login_required @@ -177,8 +208,8 @@ def group_request_leave(request, group_id): if OpenGroup.objects.filter(group=group).exists(): logger.info("%s leaving %s as is an open group" % (request.user, group)) request.user.groups.remove(group) - return HttpResponseRedirect("/groups") - auth_info = AuthServicesInfoManager.get_auth_service_info(request.user) + return redirect("auth_groups") + auth_info = AuthServicesInfo.objects.get_or_create(user=request.user)[0] grouprequest = GroupRequest() grouprequest.status = _('Pending') grouprequest.group = group @@ -187,5 +218,5 @@ def group_request_leave(request, group_id): grouprequest.leave_request = True grouprequest.save() logger.info("Created group leave request for user %s to group %s" % (request.user, Group.objects.get(id=group_id))) - - return HttpResponseRedirect("/groups") + messages.success(request, 'Applied to leave group %s.' % group) + return redirect("auth_groups") diff --git a/hrapplications/__init__.py b/hrapplications/__init__.py index e69de29b..baffc488 100644 --- a/hrapplications/__init__.py +++ b/hrapplications/__init__.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/hrapplications/admin.py b/hrapplications/admin.py index 5b7e89aa..c334cad2 100755 --- a/hrapplications/admin.py +++ b/hrapplications/admin.py @@ -1,10 +1,11 @@ +from __future__ import unicode_literals from django.contrib import admin -from models import Application -from models import ApplicationQuestion -from models import ApplicationForm -from models import ApplicationResponse -from models import ApplicationComment +from hrapplications.models import Application +from hrapplications.models import ApplicationQuestion +from hrapplications.models import ApplicationForm +from hrapplications.models import ApplicationResponse +from hrapplications.models import ApplicationComment admin.site.register(Application) admin.site.register(ApplicationComment) diff --git a/hrapplications/apps.py b/hrapplications/apps.py new file mode 100644 index 00000000..5d99de86 --- /dev/null +++ b/hrapplications/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class HRApplicationsConfig(AppConfig): + name = 'hrapplications' diff --git a/hrapplications/forms.py b/hrapplications/forms.py index 91330c4b..70842acb 100755 --- a/hrapplications/forms.py +++ b/hrapplications/forms.py @@ -1,8 +1,11 @@ +from __future__ import unicode_literals from django import forms from django.utils.translation import ugettext_lazy as _ + class HRApplicationCommentForm(forms.Form): comment = forms.CharField(widget=forms.Textarea, required=False, label=_("Comment")) + class HRApplicationSearchForm(forms.Form): search_string = forms.CharField(max_length=254, required=True, label=_("Search String")) diff --git a/hrapplications/migrations/0001_initial.py b/hrapplications/migrations/0001_initial.py new file mode 100644 index 00000000..7733ce58 --- /dev/null +++ b/hrapplications/migrations/0001_initial.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-05 21:39 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('eveonline', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Application', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('approved', models.NullBooleanField(default=None)), + ('created', models.DateTimeField(auto_now_add=True)), + ], + options={ + 'permissions': (('approve_application', 'Can approve applications'), ('reject_application', 'Can reject applications'), ('view_apis', 'Can view applicant APIs')), + }, + ), + migrations.CreateModel( + name='ApplicationComment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('text', models.TextField()), + ('created', models.DateTimeField(auto_now_add=True)), + ('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='hrapplications.Application')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='ApplicationForm', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('corp', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='eveonline.EveCorporationInfo')), + ], + ), + migrations.CreateModel( + name='ApplicationQuestion', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=254)), + ('help_text', models.CharField(blank=True, max_length=254, null=True)), + ], + ), + migrations.CreateModel( + name='ApplicationResponse', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('answer', models.TextField()), + ('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='responses', to='hrapplications.Application')), + ('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hrapplications.ApplicationQuestion')), + ], + ), + migrations.CreateModel( + name='HRApplication', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('character_name', models.CharField(default=b'', max_length=254)), + ('full_api_id', models.CharField(default=b'', max_length=254)), + ('full_api_key', models.CharField(default=b'', max_length=254)), + ('is_a_spi', models.CharField(default=b'', max_length=254)), + ('about', models.TextField(default=b'')), + ('extra', models.TextField(default=b'')), + ('approved_denied', models.NullBooleanField()), + ('corp', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eveonline.EveCorporationInfo')), + ('reviewer_character', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='eveonline.EveCharacter')), + ('reviewer_inprogress_character', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='inprogress_character', to='eveonline.EveCharacter')), + ('reviewer_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='review_user', to=settings.AUTH_USER_MODEL)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='HRApplicationComment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_on', models.DateTimeField(auto_now_add=True, null=True)), + ('comment', models.CharField(default=b'', max_length=254)), + ('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hrapplications.HRApplication')), + ('commenter_character', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eveonline.EveCharacter')), + ('commenter_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.AddField( + model_name='applicationform', + name='questions', + field=models.ManyToManyField(to='hrapplications.ApplicationQuestion'), + ), + migrations.AddField( + model_name='application', + name='form', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='applications', to='hrapplications.ApplicationForm'), + ), + migrations.AddField( + model_name='application', + name='reviewer', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='application', + name='reviewer_character', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='eveonline.EveCharacter'), + ), + migrations.AddField( + model_name='application', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='applications', to=settings.AUTH_USER_MODEL), + ), + migrations.AlterUniqueTogether( + name='applicationresponse', + unique_together=set([('question', 'application')]), + ), + migrations.AlterUniqueTogether( + name='application', + unique_together=set([('form', 'user')]), + ), + ] diff --git a/hrapplications/migrations/__init__.py b/hrapplications/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/hrapplications/models.py b/hrapplications/models.py index e0824bae..85372faa 100755 --- a/hrapplications/models.py +++ b/hrapplications/models.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals +from django.utils.encoding import python_2_unicode_compatible from django.db import models from django.contrib.auth.models import User @@ -6,6 +8,8 @@ from eveonline.models import EveCorporationInfo from eveonline.models import EveApiKeyPair from authentication.models import AuthServicesInfo + +@python_2_unicode_compatible class ApplicationQuestion(models.Model): title = models.CharField(max_length=254) help_text = models.CharField(max_length=254, blank=True, null=True) @@ -13,6 +17,8 @@ class ApplicationQuestion(models.Model): def __str__(self): return "Question: " + self.title.encode('utf-8') + +@python_2_unicode_compatible class ApplicationForm(models.Model): questions = models.ManyToManyField(ApplicationQuestion) corp = models.OneToOneField(EveCorporationInfo) @@ -20,6 +26,8 @@ class ApplicationForm(models.Model): def __str__(self): return str(self.corp) + +@python_2_unicode_compatible class Application(models.Model): form = models.ForeignKey(ApplicationForm, on_delete=models.CASCADE, related_name='applications') user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='applications') @@ -32,7 +40,9 @@ class Application(models.Model): return str(self.user) + " Application To " + str(self.form) class Meta: - permissions = (('approve_application', 'Can approve applications'), ('reject_application', 'Can reject applications'), ('view_apis', 'Can view applicant APIs'),) + permissions = ( + ('approve_application', 'Can approve applications'), ('reject_application', 'Can reject applications'), + ('view_apis', 'Can view applicant APIs'),) unique_together = ('form', 'user') @property @@ -62,6 +72,7 @@ class Application(models.Model): return None +@python_2_unicode_compatible class ApplicationResponse(models.Model): question = models.ForeignKey(ApplicationQuestion, on_delete=models.CASCADE) application = models.ForeignKey(Application, on_delete=models.CASCADE, related_name='responses') @@ -73,6 +84,8 @@ class ApplicationResponse(models.Model): class Meta: unique_together = ('question', 'application') + +@python_2_unicode_compatible class ApplicationComment(models.Model): application = models.ForeignKey(Application, on_delete=models.CASCADE, related_name='comments') user = models.ForeignKey(User, on_delete=models.CASCADE) @@ -82,12 +95,11 @@ class ApplicationComment(models.Model): def __str__(self): return str(self.user) + " comment on " + str(self.application) + ################ # Legacy Models ################ -# Can't delete or evolutions explodes. -# They do nothing. -################ +@python_2_unicode_compatible class HRApplication(models.Model): character_name = models.CharField(max_length=254, default="") full_api_id = models.CharField(max_length=254, default="") @@ -109,6 +121,7 @@ class HRApplication(models.Model): return self.character_name + " - Application" +@python_2_unicode_compatible class HRApplicationComment(models.Model): created_on = models.DateTimeField(auto_now_add=True, null=True) comment = models.CharField(max_length=254, default="") diff --git a/hrapplications/views.py b/hrapplications/views.py index 11bbebec..68787bac 100755 --- a/hrapplications/views.py +++ b/hrapplications/views.py @@ -1,30 +1,23 @@ -from django.template import RequestContext -from django.shortcuts import render_to_response, get_object_or_404, redirect +from __future__ import unicode_literals +from django.shortcuts import render, get_object_or_404, redirect from django.contrib.auth.decorators import permission_required from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import user_passes_test -from django.shortcuts import HttpResponseRedirect from notifications import notify -from models import HRApplication -from models import HRApplicationComment -from models import ApplicationForm -from models import Application -from models import ApplicationQuestion -from models import ApplicationResponse -from models import ApplicationComment -from forms import HRApplicationCommentForm -from forms import HRApplicationSearchForm -from eveonline.models import EveCorporationInfo +from hrapplications.models import ApplicationForm +from hrapplications.models import Application +from hrapplications.models import ApplicationResponse +from hrapplications.models import ApplicationComment +from hrapplications.forms import HRApplicationCommentForm +from hrapplications.forms import HRApplicationSearchForm from eveonline.models import EveCharacter from authentication.models import AuthServicesInfo -from django.conf import settings -from eveonline.managers import EveManager - import logging logger = logging.getLogger(__name__) + def create_application_test(user): auth, c = AuthServicesInfo.objects.get_or_create(user=user) if auth.main_char_id: @@ -32,6 +25,7 @@ def create_application_test(user): else: return False + @login_required def hr_application_management_view(request): logger.debug("hr_application_management_view called by user %s" % request.user) @@ -42,7 +36,7 @@ def hr_application_management_view(request): if auth_info.main_char_id: try: main_char = EveCharacter.objects.get(character_id=auth_info.main_char_id) - except: + except EveCharacter.DoesNotExist: pass if request.user.is_superuser: corp_applications = Application.objects.filter(approved=None) @@ -52,7 +46,8 @@ def hr_application_management_view(request): app_form = ApplicationForm.objects.get(corp__corporation_id=main_char.corporation_id) corp_applications = Application.objects.filter(form=app_form).filter(approved=None) finished_corp_applications = Application.objects.filter(form=app_form).filter(approved__in=[True, False]) - logger.debug("Retrieved %s personal, %s corp applications for %s" % (len(request.user.applications.all()), len(corp_applications), request.user)) + logger.debug("Retrieved %s personal, %s corp applications for %s" % ( + len(request.user.applications.all()), len(corp_applications), request.user)) context = { 'personal_apps': request.user.applications.all(), 'applications': corp_applications, @@ -60,7 +55,8 @@ def hr_application_management_view(request): 'search_form': HRApplicationSearchForm(), 'create': create_application_test(request.user) } - return render_to_response('registered/hrapplicationmanagement.html', context, context_instance=RequestContext(request)) + return render(request, 'registered/hrapplicationmanagement.html', context=context) + @login_required @user_passes_test(create_application_test) @@ -75,19 +71,22 @@ def hr_application_create_view(request, form_id=None): application.save() for question in app_form.questions.all(): response = ApplicationResponse(question=question, application=application) - response.answer = request.POST.get(str(question.pk), "Failed to retrieve answer provided by applicant.") + response.answer = request.POST.get(str(question.pk), + "Failed to retrieve answer provided by applicant.") response.save() logger.info("%s created %s" % (request.user, application)) return redirect('auth_hrapplications_view') else: questions = app_form.questions.all() - return render_to_response('registered/hrapplicationcreate.html', {'questions':questions, 'corp':app_form.corp}, context_instance=RequestContext(request)) + return render(request, 'registered/hrapplicationcreate.html', + context={'questions': questions, 'corp': app_form.corp}) else: choices = [] for app_form in ApplicationForm.objects.all(): if not Application.objects.filter(user=request.user).filter(form=app_form).exists(): choices.append((app_form.id, app_form.corp.corporation_name)) - return render_to_response('registered/hrapplicationcorpchoice.html', {'choices':choices}, context_instance=RequestContext(request)) + return render(request, 'registered/hrapplicationcorpchoice.html', context={'choices': choices}) + @login_required def hr_application_personal_view(request, app_id): @@ -102,18 +101,18 @@ def hr_application_personal_view(request, app_id): 'comment_form': HRApplicationCommentForm(), 'apis': [], } - return render_to_response('registered/hrapplicationview.html', context, context_instance=RequestContext(request)) + return render(request, 'registered/hrapplicationview.html', context=context) else: logger.warn("User %s not authorized to view %s" % (request.user, app)) return redirect('auth_hrapplications_view') - + @login_required def hr_application_personal_removal(request, app_id): logger.debug("hr_application_personal_removal called by user %s for app id %s" % (request.user, app_id)) app = get_object_or_404(Application, pk=app_id) if app.user == request.user: - if app.approved == None: + if app.approved is None: logger.info("User %s deleting %s" % (request.user, app)) app.delete() else: @@ -122,6 +121,7 @@ def hr_application_personal_removal(request, app_id): logger.warn("User %s not authorized to delete %s" % (request.user, app)) return redirect('auth_hrapplications_view') + @login_required @permission_required('auth.human_resources') def hr_application_view(request, app_id): @@ -154,7 +154,7 @@ def hr_application_view(request, app_id): 'comments': ApplicationComment.objects.filter(application=app), 'comment_form': form, } - return render_to_response('registered/hrapplicationview.html', context, context_instance=RequestContext(request)) + return render(request, 'registered/hrapplicationview.html', context=context) @login_required @@ -168,6 +168,7 @@ def hr_application_remove(request, app_id): notify(app.user, "Application Deleted", message="Your application to %s was deleted." % app.form.corp) return redirect('auth_hrapplications_view') + @login_required @permission_required('auth.human_resources') @permission_required('hrapplications.approve_application') @@ -178,11 +179,13 @@ def hr_application_approve(request, app_id): logger.info("User %s approving %s" % (request.user, app)) app.approved = True app.save() - notify(app.user, "Application Accepted", message="Your application to %s has been approved." % app.form.corp, level="success") + notify(app.user, "Application Accepted", message="Your application to %s has been approved." % app.form.corp, + level="success") else: logger.warn("User %s not authorized to approve %s" % (request.user, app)) return redirect('auth_hrapplications_view') + @login_required @permission_required('auth.human_resources') @permission_required('hrapplications.reject_application') @@ -193,11 +196,13 @@ def hr_application_reject(request, app_id): logger.info("User %s rejecting %s" % (request.user, app)) app.approved = False app.save() - notify(app.user, "Application Rejected", message="Your application to %s has been rejected." % app.form.corp, level="danger") + notify(app.user, "Application Rejected", message="Your application to %s has been rejected." % app.form.corp, + level="danger") else: logger.warn("User %s not authorized to reject %s" % (request.user, app)) return redirect('auth_hrapplications_view') + @login_required @permission_required('auth.human_resources') def hr_application_search(request): @@ -217,15 +222,16 @@ def hr_application_search(request): try: character = EveCharacter.objects.get(character_id=auth_info.main_char_id) app_list = Application.objects.filter(form__corp__corporation_id=character.corporation_id) - except: - logger.warn("User %s missing main character model: unable to filter applications to search" % request.user) + except EveCharacter.DoesNotExist: + logger.warn( + "User %s missing main character model: unable to filter applications to search" % request.user) for application in app_list: if application.main_character: if searchstring in application.main_character.character_name.lower(): applications.add(application) if searchstring in application.main_character.corporation_name.lower(): applications.add(application) - if searchstring in application.main_character.alliance_name.lower():\ + if searchstring in application.main_character.alliance_name.lower(): applications.add(application) for character in application.characters: if searchstring in character.character_name.lower(): @@ -236,21 +242,21 @@ def hr_application_search(request): applications.add(application) if searchstring in application.user.username.lower(): applications.add(application) - logger.info("Found %s Applications for user %s matching search string %s" % (len(applications), request.user, searchstring)) + logger.info("Found %s Applications for user %s matching search string %s" % ( + len(applications), request.user, searchstring)) context = {'applications': applications, 'search_form': HRApplicationSearchForm()} - return render_to_response('registered/hrapplicationsearchview.html', - context, context_instance=RequestContext(request)) + return render(request, 'registered/hrapplicationsearchview.html', context=context) else: logger.debug("Form invalid - returning for user %s to retry." % request.user) context = {'applications': None, 'search_form': form} - return render_to_response('registered/hrapplicationsearchview.html', - context, context_instance=RequestContext(request)) + return render(request, 'registered/hrapplicationsearchview.html', context=context) else: logger.debug("Returning empty search form for user %s" % request.user) - return HttpResponseRedirect("/hr_application_management/") + return redirect("auth_hrapplications_view") + @login_required @permission_required('auth.human_resources') @@ -262,13 +268,15 @@ def hr_application_mark_in_progress(request, app_id): auth_info = AuthServicesInfo.objects.get(user=request.user) try: character = EveCharacter.objects.get(character_id=auth_info.main_char_id) - except: + except EveCharacter.DoesNotExist: logger.warn("User %s marking %s in review has no main character" % (request.user, app)) character = None app.reviewer = request.user app.reviewer_character = character app.save() - notify(app.user, "Application In Progress", message="Your application to %s is being reviewed by %s" % (app.form.corp, app.reviewer_str)) + notify(app.user, "Application In Progress", + message="Your application to %s is being reviewed by %s" % (app.form.corp, app.reviewer_str)) else: - logger.warn("User %s unable to mark %s in progress: already being reviewed by %s" % (request.user, app, app.reviewer)) - return HttpResponseRedirect("/hr_application_view/" + str(app_id)) + logger.warn( + "User %s unable to mark %s in progress: already being reviewed by %s" % (request.user, app, app.reviewer)) + return redirect("auth_hrapplication_view", app_id) diff --git a/manage.py b/manage.py index 7cb0a0af..b65130b0 100644 --- a/manage.py +++ b/manage.py @@ -1,10 +1,23 @@ #!/usr/bin/env python +from __future__ import unicode_literals import os import sys if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "alliance_auth.settings") - - from django.core.management import execute_from_command_line - + try: + from django.core.management import execute_from_command_line + except ImportError: + # The above import may fail for some other reason. Ensure that the + # issue is really that Django is missing to avoid masking other + # exceptions on Python 2. + try: + import django + except ImportError: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) + raise execute_from_command_line(sys.argv) diff --git a/notifications/__init__.py b/notifications/__init__.py index 67bb4cca..be26720d 100644 --- a/notifications/__init__.py +++ b/notifications/__init__.py @@ -1,11 +1,13 @@ -from .models import Notification +from __future__ import unicode_literals import logging logger = logging.getLogger(__name__) MAX_NOTIFICATIONS = 50 + def notify(user, title, message=None, level='info'): + from .models import Notification if Notification.objects.filter(user=user).count() > MAX_NOTIFICATIONS: for n in Notification.objects.filter(user=user)[MAX_NOTIFICATIONS:]: n.delete() diff --git a/notifications/admin.py b/notifications/admin.py index 56893293..c9bd4f21 100644 --- a/notifications/admin.py +++ b/notifications/admin.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals from django.contrib import admin from.models import Notification diff --git a/notifications/apps.py b/notifications/apps.py new file mode 100644 index 00000000..6e5c9743 --- /dev/null +++ b/notifications/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class NotificationsConfig(AppConfig): + name = 'notifications' diff --git a/notifications/context_processors.py b/notifications/context_processors.py index 1c9a5385..97d05923 100644 --- a/notifications/context_processors.py +++ b/notifications/context_processors.py @@ -1,4 +1,6 @@ -from .models import Notification +from __future__ import unicode_literals +from notifications.models import Notification + def user_notification_count(request): - return {'notifications':len(Notification.objects.filter(user__id=request.user.id).filter(viewed=False))} + return {'notifications': len(Notification.objects.filter(user__id=request.user.id).filter(viewed=False))} diff --git a/notifications/handlers.py b/notifications/handlers.py index 720ed07c..6330fc49 100644 --- a/notifications/handlers.py +++ b/notifications/handlers.py @@ -1,11 +1,13 @@ +from __future__ import unicode_literals import logging -from django.contrib.auth.models import User -from .models import Notification logger = logging.getLogger(__name__) + class NotificationHandler(logging.Handler): def emit(self, record): + from django.contrib.auth.models import User + from notifications.models import Notification for user in User.objects.all(): if user.has_perm('auth.logging_notifications'): notif = Notification() @@ -14,7 +16,7 @@ class NotificationHandler(logging.Handler): notif.level = str([item[0] for item in Notification.LEVEL_CHOICES if item[1] == record.levelname][0]) message = record.getMessage() if record.exc_text: - message = message + "\n\n" + message += "\n\n" message = message + record.exc_text notif.message = message notif.save() diff --git a/notifications/migrations/0001_initial.py b/notifications/migrations/0001_initial.py new file mode 100644 index 00000000..68fdd90e --- /dev/null +++ b/notifications/migrations/0001_initial.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-05 21:40 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Notification', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('level', models.CharField(choices=[(b'danger', b'CRITICAL'), (b'danger', b'ERROR'), (b'warning', b'WARN'), (b'info', b'INFO'), (b'success', b'DEBUG')], max_length=10)), + ('title', models.CharField(max_length=254)), + ('message', models.TextField()), + ('timestamp', models.DateTimeField(auto_now_add=True)), + ('viewed', models.BooleanField(default=False)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/notifications/migrations/0002_auto_20160910_1649.py b/notifications/migrations/0002_auto_20160910_1649.py new file mode 100644 index 00000000..f077fec0 --- /dev/null +++ b/notifications/migrations/0002_auto_20160910_1649.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-10 16:49 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('notifications', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='notification', + options={'ordering': ['-timestamp']}, + ), + ] diff --git a/notifications/migrations/__init__.py b/notifications/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/notifications/models.py b/notifications/models.py index cf0d688d..a102139f 100644 --- a/notifications/models.py +++ b/notifications/models.py @@ -1,11 +1,14 @@ +from __future__ import unicode_literals +from django.utils.encoding import python_2_unicode_compatible from django.db import models from django.contrib.auth.models import User import logging logger = logging.getLogger(__name__) -class Notification(models.Model): +@python_2_unicode_compatible +class Notification(models.Model): LEVEL_CHOICES = ( ('danger', 'CRITICAL'), ('danger', 'ERROR'), @@ -26,9 +29,11 @@ class Notification(models.Model): self.viewed = True self.save() - def __unicode__(self): - output = "%s: %s" % (self.user, self.title) - return output.encode('utf-8') + def __str__(self): + return "%s: %s" % (self.user, self.title) def set_level(self, level): self.level = [item[0] for item in self.LEVEL_CHOICES if item[1] == level][0] + + class Meta: + ordering = ['-timestamp'] diff --git a/notifications/tests.py b/notifications/tests.py index 7ce503c2..a39b155a 100644 --- a/notifications/tests.py +++ b/notifications/tests.py @@ -1,3 +1 @@ -from django.test import TestCase - # Create your tests here. diff --git a/notifications/views.py b/notifications/views.py index c6252cb7..201d7c9f 100644 --- a/notifications/views.py +++ b/notifications/views.py @@ -1,10 +1,13 @@ +from __future__ import unicode_literals from django.shortcuts import render, get_object_or_404, redirect from .models import Notification from django.contrib.auth.decorators import login_required +from django.contrib import messages import logging logger = logging.getLogger(__name__) + @login_required def notification_list(request): logger.debug("notification_list called by user %s" % request.user) @@ -17,6 +20,7 @@ def notification_list(request): } return render(request, 'registered/notification_list.html', context) + @login_required def notification_view(request, notif_id): logger.debug("notification_view called by user %s for notif_id %s" % (request.user, notif_id)) @@ -27,9 +31,12 @@ def notification_view(request, notif_id): notif.view() return render(request, 'registered/notification_view.html', context) else: - logger.warn("User %s not authorized to view notif_id %s belonging to user %s" % (request.user, notif_id, notif.user)) + logger.warn( + "User %s not authorized to view notif_id %s belonging to user %s" % (request.user, notif_id, notif.user)) + messages.error(request, 'You are not authorized to view that notification.') return redirect('auth_notification_list') + @login_required def remove_notification(request, notif_id): logger.debug("remove notification called by user %s for notif_id %s" % (request.user, notif_id)) @@ -38,6 +45,25 @@ def remove_notification(request, notif_id): if Notification.objects.filter(id=notif_id).exists(): notif.delete() logger.info("Deleting notif id %s by user %s" % (notif_id, request.user)) + messages.success(request, 'Deleted notification.') else: - logger.error("Unable to delete notif id %s for user %s - notif matching id not found." % (notif_id, request.user)) + logger.error( + "Unable to delete notif id %s for user %s - notif matching id not found." % (notif_id, request.user)) + messages.error(request, 'Failed to locate notification.') + return redirect('auth_notification_list') + + +@login_required +def mark_all_read(request): + logger.debug('mark all notifications read called by user %s' % request.user) + Notification.objects.filter(user=request.user).update(viewed=True) + messages.success(request, 'Marked all notifications as read.') + return redirect('auth_notification_list') + + +@login_required +def delete_all_read(request): + logger.debug('delete all read notifications called by user %s' % request.user) + Notification.objects.filter(user=request.user).filter(viewed=True).delete() + messages.success(request, 'Deleted all read notifications.') return redirect('auth_notification_list') diff --git a/optimer/__init__.py b/optimer/__init__.py index e69de29b..baffc488 100644 --- a/optimer/__init__.py +++ b/optimer/__init__.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/optimer/admin.py b/optimer/admin.py index 85271e70..fd962cbe 100644 --- a/optimer/admin.py +++ b/optimer/admin.py @@ -1,6 +1,6 @@ +from __future__ import unicode_literals from django.contrib import admin -from models import optimer +from optimer.models import optimer admin.site.register(optimer) -# Register your models here. diff --git a/optimer/apps.py b/optimer/apps.py new file mode 100644 index 00000000..9b2a9052 --- /dev/null +++ b/optimer/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class OptimerConfig(AppConfig): + name = 'optimer' diff --git a/optimer/form.py b/optimer/form.py index fbf15e13..6e476677 100644 --- a/optimer/form.py +++ b/optimer/form.py @@ -1,11 +1,9 @@ +from __future__ import unicode_literals from django import forms -from django.core.validators import MaxValueValidator, MinValueValidator from django.utils.translation import ugettext_lazy as _ - class opForm(forms.Form): - doctrine = forms.CharField(max_length=254, required=True, label=_('Doctrine')) system = forms.CharField(max_length=254, required=True, label=_("System")) location = forms.CharField(max_length=254, required=True, label=_("Location")) diff --git a/optimer/migrations/0001_initial.py b/optimer/migrations/0001_initial.py new file mode 100644 index 00000000..3b31c2ac --- /dev/null +++ b/optimer/migrations/0001_initial.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-05 21:40 +from __future__ import unicode_literals + +import datetime +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('eveonline', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='optimer', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('doctrine', models.CharField(default=b'', max_length=254)), + ('system', models.CharField(default=b'', max_length=254)), + ('location', models.CharField(default=b'', max_length=254)), + ('start', models.DateTimeField(default=datetime.datetime.now)), + ('duration', models.CharField(default=b'', max_length=25)), + ('operation_name', models.CharField(default=b'', max_length=254)), + ('fc', models.CharField(default=b'', max_length=254)), + ('details', models.CharField(default=b'', max_length=254)), + ('post_time', models.DateTimeField(default=django.utils.timezone.now)), + ('eve_character', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eveonline.EveCharacter')), + ], + options={ + 'ordering': ['start'], + }, + ), + ] diff --git a/optimer/migrations/__init__.py b/optimer/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/optimer/models.py b/optimer/models.py index 583997cf..32670bf0 100644 --- a/optimer/models.py +++ b/optimer/models.py @@ -1,14 +1,16 @@ +from __future__ import unicode_literals +from django.utils.encoding import python_2_unicode_compatible from django.db import models -from django.contrib.auth.models import User from django.utils import timezone from eveonline.models import EveCharacter -from eveonline.models import EveCorporationInfo from datetime import datetime +@python_2_unicode_compatible class optimer(models.Model): class Meta: ordering = ['start'] + doctrine = models.CharField(max_length=254, default="") system = models.CharField(max_length=254, default="") location = models.CharField(max_length=254, default="") @@ -23,4 +25,3 @@ class optimer(models.Model): def __str__(self): output = self.operation_name return output.encode('utf-8') - diff --git a/optimer/views.py b/optimer/views.py index 6d130fe3..558a9397 100644 --- a/optimer/views.py +++ b/optimer/views.py @@ -1,38 +1,29 @@ - - -from django.http import HttpResponseRedirect -from django.template import RequestContext -from django.shortcuts import render_to_response +from __future__ import unicode_literals from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import permission_required -from django.contrib.auth.decorators import user_passes_test from django.utils import timezone from django.shortcuts import get_object_or_404 - -from util import check_if_user_has_permission -from authentication.managers import AuthServicesInfoManager +from django.shortcuts import render, redirect +from django.contrib import messages +from authentication.models import AuthServicesInfo from eveonline.managers import EveManager -from form import opForm -from models import optimer - +from optimer.form import opForm +from optimer.models import optimer +from authentication.decorators import members_and_blues import logging logger = logging.getLogger(__name__) -def optimer_util_test(user): - return check_if_user_has_permission(user, 'member') or check_if_user_has_permission(user, 'blue_member') - @login_required -@user_passes_test(optimer_util_test) +@members_and_blues() @permission_required('auth.optimer_view') def optimer_view(request): logger.debug("optimer_view called by user %s" % request.user) - optimer_list = optimer.objects.all() - render_items = {'optimer': optimer.objects.all(),} + render_items = {'optimer': optimer.objects.all(), } - return render_to_response('registered/operationmanagement.html', render_items, context_instance=RequestContext(request)) + return render(request, 'registered/operationmanagement.html', context=render_items) @login_required @@ -40,13 +31,13 @@ def optimer_view(request): def add_optimer_view(request): logger.debug("add_optimer_view called by user %s" % request.user) if request.method == 'POST': - form = opForm(request.POST) - logger.debug("Request type POST contains form valid: %s" % form.is_valid()) + form = opForm(request.POST) + logger.debug("Request type POST contains form valid: %s" % form.is_valid()) if form.is_valid(): - #Get Current Time + # Get Current Time post_time = timezone.now() # Get character - auth_info = AuthServicesInfoManager.get_auth_service_info(request.user) + auth_info = AuthServicesInfo.objects.get_or_create(user=request.user)[0] character = EveManager.get_character_by_id(auth_info.main_char_id) # handle valid form op = optimer() @@ -62,14 +53,15 @@ def add_optimer_view(request): op.eve_character = character op.save() logger.info("User %s created op timer with name %s" % (request.user, op.operation_name)) - return HttpResponseRedirect("/optimer/") + messages.success(request, 'Created operation timer for %s.' % op.operation_name) + return redirect("/optimer/") else: logger.debug("Returning new opForm") form = opForm() render_items = {'form': form} - return render_to_response('registered/addoperation.html', render_items, context_instance=RequestContext(request)) + return render(request, 'registered/addoperation.html', context=render_items) @login_required @@ -80,9 +72,12 @@ def remove_optimer(request, optimer_id): op = optimer.objects.get(id=optimer_id) op.delete() logger.info("Deleting optimer id %s by user %s" % (optimer_id, request.user)) + messages.success(request, 'Removed operation timer for %s.' % op.operation_name) else: - logger.error("Unable to delete optimer id %s for user %s - operation matching id not found." % (optimer_id, request.user)) - return HttpResponseRedirect("/optimer/") + logger.error("Unable to delete optimer id %s for user %s - operation matching id not found." % ( + optimer_id, request.user)) + return redirect("auth_optimer_view") + @login_required @permission_required('auth.optimer_management') @@ -93,7 +88,7 @@ def edit_optimer(request, optimer_id): form = opForm(request.POST) logger.debug("Received POST request containing update optimer form, is valid: %s" % form.is_valid()) if form.is_valid(): - auth_info = AuthServicesInfoManager.get_auth_service_info(request.user) + auth_info = AuthServicesInfo.objects.get_or_create(user=request.user)[0] character = EveManager.get_character_by_id(auth_info.main_char_id) op.doctrine = form.cleaned_data['doctrine'] op.system = form.cleaned_data['system'] @@ -106,9 +101,8 @@ def edit_optimer(request, optimer_id): op.eve_character = character logger.info("User %s updating optimer id %s " % (request.user, optimer_id)) op.save() - - logger.debug("Detected no changes between optimer id %s and supplied form." % optimer_id) - return HttpResponseRedirect("/optimer/") + messages.success(request, 'Saved changes to operation timer for %s.' % op.operation_name) + return redirect("auth_optimer_view") else: data = { 'doctrine': op.doctrine, @@ -120,5 +114,5 @@ def edit_optimer(request, optimer_id): 'fc': op.fc, 'details': op.details, } - form = opForm(initial= data) - return render_to_response('registered/optimerupdate.html', {'form':form}, context_instance=RequestContext(request)) + form = opForm(initial=data) + return render(request, 'registered/optimerupdate.html', context={'form': form}) diff --git a/portal/admin.py b/portal/admin.py deleted file mode 100644 index 846f6b40..00000000 --- a/portal/admin.py +++ /dev/null @@ -1 +0,0 @@ -# Register your models here. diff --git a/portal/models.py b/portal/models.py deleted file mode 100644 index 6b202199..00000000 --- a/portal/models.py +++ /dev/null @@ -1 +0,0 @@ -# Create your models here. diff --git a/portal/tests.py b/portal/tests.py deleted file mode 100644 index a39b155a..00000000 --- a/portal/tests.py +++ /dev/null @@ -1 +0,0 @@ -# Create your tests here. diff --git a/portal/views.py b/portal/views.py deleted file mode 100755 index 32ec7309..00000000 --- a/portal/views.py +++ /dev/null @@ -1,30 +0,0 @@ -from django.template import RequestContext -from django.shortcuts import render_to_response -from django.contrib.auth.decorators import login_required - -from eveonline.managers import EveManager -from authentication.managers import AuthServicesInfoManager - -import logging - -logger = logging.getLogger(__name__) - - -# Create your views here. -def index_view(request): - logger.debug("index_view called by user %s" % request.user) - return render_to_response('public/index.html', None, context_instance=RequestContext(request)) - - -@login_required -def dashboard_view(request): - logger.debug("dashboard_view called by user %s" % request.user) - render_items = {'characters': EveManager.get_characters_by_owner_id(request.user.id), - 'authinfo': AuthServicesInfoManager.get_auth_service_info(request.user)} - return render_to_response('registered/dashboard.html', render_items, context_instance=RequestContext(request)) - - -@login_required -def help_view(request): - logger.debug("help_view called by user %s" % request.user) - return render_to_response('registered/help.html', None, context_instance=RequestContext(request)) diff --git a/registration/admin.py b/registration/admin.py deleted file mode 100644 index 846f6b40..00000000 --- a/registration/admin.py +++ /dev/null @@ -1 +0,0 @@ -# Register your models here. diff --git a/registration/forms.py b/registration/forms.py deleted file mode 100644 index f0a39931..00000000 --- a/registration/forms.py +++ /dev/null @@ -1,44 +0,0 @@ -from django import forms -from django.contrib.auth.models import User -from django.utils.translation import ugettext_lazy as _ -import re - -import logging - -logger = logging.getLogger(__name__) - -class RegistrationForm(forms.Form): - username = forms.CharField(label=_('Username'), max_length=30, required=True) - password = forms.CharField(label=_('Password'), widget=forms.PasswordInput(), required=True) - password_again = forms.CharField(label=_('Password Again'), widget=forms.PasswordInput(), required=True) - email = forms.CharField(label=_('Email'), max_length=254, required=True) - email_again = forms.CharField(label=_('Email Again'), max_length=254, required=True) - - def clean(self): - if ' ' in self.cleaned_data['username']: - logger.debug("RegistrationForm username contains spaces. Raising ValidationError. Username: %s" % self.cleaned_data['username']) - raise forms.ValidationError(u'Username cannot contain a space') - - # We attempt to get the user object if we succeed we know email as been used - try: - User.objects.get(email=self.cleaned_data['email']) - logger.debug("RegistrationForm email already registered. Raising ValidationError") - raise forms.ValidationError(u'Email as already been used') - except: - pass - - if not re.match("^\w+$", self.cleaned_data['username']): - logger.debug("RegistrationForm username contains non-alphanumeric characters. Raising ValueError. Username: %s" % self.cleaned_data['username']) - raise forms.ValidationError(u'Username contains illegal characters') - - if 'password' in self.cleaned_data and 'password_again' in self.cleaned_data: - if self.cleaned_data['password'] != self.cleaned_data['password_again']: - logger.debug("RegistrationForm password mismatch. Raising ValueError") - raise forms.ValidationError(u'Passwords do not match') - - if 'email' in self.cleaned_data and 'email_again' in self.cleaned_data: - if self.cleaned_data['email'] != self.cleaned_data['email_again']: - logger.debug("RegistrationForm email mismatch. Raising ValidationError") - raise forms.ValidationError(u'Emails do not match') - - return self.cleaned_data diff --git a/registration/models.py b/registration/models.py deleted file mode 100644 index 6b202199..00000000 --- a/registration/models.py +++ /dev/null @@ -1 +0,0 @@ -# Create your models here. diff --git a/registration/tests.py b/registration/tests.py deleted file mode 100644 index a39b155a..00000000 --- a/registration/tests.py +++ /dev/null @@ -1 +0,0 @@ -# Create your tests here. diff --git a/registration/views.py b/registration/views.py deleted file mode 100644 index 59e0658a..00000000 --- a/registration/views.py +++ /dev/null @@ -1,40 +0,0 @@ -from django.contrib.auth.models import User -from django.http import HttpResponseRedirect -from django.shortcuts import render_to_response -from django.template import RequestContext -from django.utils import translation - -from forms import RegistrationForm - -import logging - -logger = logging.getLogger(__name__) - -def register_user_view(request): - logger.debug("register_user_view called by user %s" % request.user) - if request.method == 'POST': - form = RegistrationForm(request.POST) - logger.debug("Request type POST contains form valid: %s" % form.is_valid()) - if form.is_valid(): - - if not User.objects.filter(username=form.cleaned_data['username']).exists(): - user = User.objects.create_user(form.cleaned_data['username'], - form.cleaned_data['email'], form.cleaned_data['password']) - - user.save() - logger.info("Created new user %s" % user) - - return HttpResponseRedirect("/dashboard/") - - else: - logger.error("Unable to register new user: username %s already exists." % form.cleaned_data['username']) - return render_to_response('public/register.html', {'form': form, 'error': True} - , context_instance=RequestContext(request)) - else: - logger.debug("Registration form invalid. Returning for user %s to make corrections." % request.user) - - else: - logger.debug("Returning blank registration form.") - form = RegistrationForm() - - return render_to_response('public/register.html', {'form': form}, context_instance=RequestContext(request)) diff --git a/requirements.txt b/requirements.txt index 23106c9a..e4223b4c 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,21 +1,25 @@ # Python Stuff # - see bootstrap.sh -mysql-python mysqlclient evelink dnspython passlib requests>=2.9.1 bcrypt -zeroc-ice +#zeroc-ice slugify requests-oauthlib +sleekxmpp # Django Stuff # -django==1.6.5 -django-evolution +django>=1.10,<2.0 django-bootstrap-form -django-celery +django-navhelper + +# awating release for fix to celery/django-celery#447 +# django-celery +git+https://github.com/celery/django-celery git+git://github.com/nikdoof/python-ts3.git -git+git://github.com/seamus-45/openfire-restapi.git -git+https://github.com/ArchipelProject/xmpppy +git+https://github.com/pyghassen/openfire-restapi + +git+https://github.com/adarnof/adarnauth-eve-sso diff --git a/run_alliance_corp_update.py b/run_alliance_corp_update.py index 05b31ecc..938961d9 100644 --- a/run_alliance_corp_update.py +++ b/run_alliance_corp_update.py @@ -1,6 +1,5 @@ -from util import bootstrap_permissions -from celerytask.tasks import run_corp_update +from __future__ import unicode_literals +from eveonline.tasks import run_corp_update -bootstrap_permissions() run_corp_update() quit() diff --git a/services/__init__.py b/services/__init__.py index e69de29b..5f118bbb 100644 --- a/services/__init__.py +++ b/services/__init__.py @@ -0,0 +1,2 @@ +from __future__ import unicode_literals +default_app_config = 'services.apps.ServicesConfig' diff --git a/services/admin.py b/services/admin.py index 1ea2f541..cfb11651 100644 --- a/services/admin.py +++ b/services/admin.py @@ -1,13 +1,15 @@ +from __future__ import unicode_literals from django.contrib import admin -from .models import AuthTS -from .models import DiscordAuthToken -from .models import MumbleUser -from .models import GroupCache +from services.models import AuthTS +from services.models import MumbleUser +from services.models import GroupCache + class AuthTSgroupAdmin(admin.ModelAdmin): - fields = ['auth_group','ts_group'] + fields = ['auth_group', 'ts_group'] filter_horizontal = ('ts_group',) + admin.site.register(AuthTS, AuthTSgroupAdmin) admin.site.register(MumbleUser) diff --git a/services/apps.py b/services/apps.py new file mode 100644 index 00000000..7b4755de --- /dev/null +++ b/services/apps.py @@ -0,0 +1,10 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class ServicesConfig(AppConfig): + name = 'services' + + def ready(self): + import services.signals \ No newline at end of file diff --git a/services/context_processors.py b/services/context_processors.py new file mode 100644 index 00000000..35bfadfc --- /dev/null +++ b/services/context_processors.py @@ -0,0 +1,31 @@ +from __future__ import unicode_literals +from django.conf import settings +from django.utils import timezone + + +def auth_settings(request): + return { + 'DOMAIN': settings.DOMAIN, + 'MUMBLE_URL': settings.MUMBLE_URL, + 'FORUM_URL': settings.FORUM_URL, + 'TEAMSPEAK3_PUBLIC_URL': settings.TEAMSPEAK3_PUBLIC_URL, + 'JACK_KNIFE_URL': settings.JACK_KNIFE_URL, + 'DISCORD_SERVER_ID': settings.DISCORD_GUILD_ID, + 'KILLBOARD_URL': settings.KILLBOARD_URL, + 'DISCOURSE_URL': settings.DISCOURSE_URL, + 'IPS4_URL': settings.IPS4_URL, + 'SMF_URL': settings.SMF_URL, + 'MARKET_URL': settings.MARKET_URL, + 'EXTERNAL_MEDIA_URL': settings.EXTERNAL_MEDIA_URL, + 'CURRENT_UTC_TIME': timezone.now(), + 'BLUE_API_MASK': settings.BLUE_API_MASK, + 'BLUE_API_ACCOUNT': settings.BLUE_API_ACCOUNT, + 'MEMBER_API_MASK': settings.MEMBER_API_MASK, + 'MEMBER_API_ACCOUNT': settings.MEMBER_API_ACCOUNT, + 'JABBER_URL': settings.JABBER_URL, + 'ALLIANCE_NAME': settings.ALLIANCE_NAME, + 'ALLIANCE_ID': settings.ALLIANCE_ID, + 'CORP_NAME': settings.CORP_NAME, + 'CORP_ID': settings.CORP_ID, + 'IS_CORP': settings.IS_CORP, + } \ No newline at end of file diff --git a/services/forms.py b/services/forms.py index 19501a29..4d97c738 100644 --- a/services/forms.py +++ b/services/forms.py @@ -1,7 +1,9 @@ +from __future__ import unicode_literals from django import forms from services.managers.teamspeak3_manager import Teamspeak3Manager from django.utils.translation import ugettext_lazy as _ + class JabberBroadcastForm(forms.Form): group = forms.ChoiceField(label=_('Group'), widget=forms.Select) message = forms.CharField(label=_('Message'), widget=forms.Textarea) @@ -17,23 +19,29 @@ class FleetFormatterForm(forms.Form): formup_time = forms.CharField(label=_('Formup Time:'), required=True) expected_duration = forms.CharField(label=_('Expected Duration:'), required=True) purpose = forms.CharField(label=_('Purpose:'), required=True) - reimbursable = forms.ChoiceField(label=_('Reimbursable?*'), choices=[(_('Yes'), _('Yes')), (_('No'), _('No'))], required=True) - important = forms.ChoiceField(label=_('Important?*'), choices=[(_('Yes'), _('Yes')), (_('No'), _('No'))], required=True) + reimbursable = forms.ChoiceField(label=_('Reimbursable?*'), choices=[(_('Yes'), _('Yes')), (_('No'), _('No'))], + required=True) + important = forms.ChoiceField(label=_('Important?*'), choices=[(_('Yes'), _('Yes')), (_('No'), _('No'))], + required=True) comments = forms.CharField(label=_('Comments'), widget=forms.Textarea, required=False) + class DiscordForm(forms.Form): email = forms.CharField(label=_("Email Address"), required=True) password = forms.CharField(label=_("Password"), required=True, widget=forms.PasswordInput) update_avatar = forms.BooleanField(label=_("Update Avatar"), required=False, initial=True) + class ServicePasswordForm(forms.Form): password = forms.CharField(label=_("Password"), required=True) + def clean_password(self): password = self.cleaned_data['password'] if not len(password) >= 8: raise forms.ValidationError(_("Password must be at least 8 characters long.")) return password + class TeamspeakJoinForm(forms.Form): username = forms.CharField(widget=forms.HiddenInput()) diff --git a/services/managers/__init__.py b/services/managers/__init__.py index e69de29b..baffc488 100644 --- a/services/managers/__init__.py +++ b/services/managers/__init__.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/services/managers/discord_manager.py b/services/managers/discord_manager.py index 5bc66e1c..4e5ee2cd 100644 --- a/services/managers/discord_manager.py +++ b/services/managers/discord_manager.py @@ -1,11 +1,9 @@ +from __future__ import unicode_literals import requests import json -from django.conf import settings import re -import os -import urllib -import base64 -from services.models import DiscordAuthToken, GroupCache +from django.conf import settings +from services.models import GroupCache from requests_oauthlib import OAuth2Session import logging import datetime @@ -16,442 +14,10 @@ logger = logging.getLogger(__name__) DISCORD_URL = "https://discordapp.com/api" EVE_IMAGE_SERVER = "https://image.eveonline.com" -class DiscordAPIManager: - - def __init__(self, server_id, email, password, user=None): - self.token = DiscordAPIManager.get_token_by_user(email, password, user) - self.email = email - self.password = password - self.server_id = server_id - logger.debug("Initialized DiscordAPIManager with server id %s" % self.server_id) - - @staticmethod - def validate_token(token): - custom_headers = {'accept': 'application/json', 'authorization': token} - path = DISCORD_URL + "/users/@me" - r = requests.get(path, headers=custom_headers) - if r.status_code == 200: - logger.debug("Token starting with %s passed validation." % token[0:5]) - return True - else: - logger.debug("Token starting with %s failed validation with status code %s" % (token[0:5], r.status_code)) - return False - - @staticmethod - def get_auth_token(): - data = { - "email" : settings.DISCORD_USER_EMAIL, - "password": settings.DISCORD_USER_PASSWORD, - } - custom_headers = {'content-type':'application/json'} - path = DISCORD_URL + "/auth/login" - r = requests.post(path, headers=custom_headers, data=json.dumps(data)) - logger.debug("Received status code %s during token generation for settings discord user." % r.status_code) - r.raise_for_status() - return r.json()['token'] - - def add_server(self, name): - data = {"name": name} - custom_headers = {'content-type':'application/json', 'authorization': self.token} - path = DISCORD_URL + "/guilds" - r = requests.post(path, headers=custom_headers, data=json.dumps(data)) - r.raise_for_status() - return r.json() - - def rename_server(self, name): - data = {"name": name} - custom_headers = {'content-type':'application/json', 'authorization': self.token} - path = DISCORD_URL + "/guilds/" + str(self.server_id) - r = requests.patch(path, headers=custom_headers, data=json.dumps(data)) - r.raise_for_status() - return r.json() - - def delete_server(self): - custom_headers = {'content-type':'application/json', 'authorization': self.token} - path = DISCORD_URL + "/guilds/" + str(self.server_id) - r = requests.delete(path, headers=custom_headers) - r.raise_for_status() - - def get_members(self): - custom_headers = {'accept':'application/json', 'authorization': self.token} - path = DISCORD_URL + "/guilds/" + str(self.server_id) + "/members" - r = requests.get(path, headers=custom_headers) - r.raise_for_status() - return r.json() - - def get_bans(self): - custom_headers = {'accept':'application/json', 'authorization': self.token} - path = DISCORD_URL + "/guilds/" + str(self.server_id) + "/bans" - r = requests.get(path, headers=custom_headers) - r.raise_for_status() - return r.json() - - def ban_user(self, user_id, delete_message_age=0): - custom_headers = {'authorization': self.token} - path = DISCORD_URL + "/guilds/" + str(self.server_id) + "/bans/" + str(user_id) + "?delete-message-days=" + str(delete_message_age) - r = requests.put(path, headers=custom_headers) - logger.debug("Received status code %s after banning user %s" % (r.status_code, user_id)) - r.raise_for_status() - - def unban_user(self, user_id): - custom_headers = {'authorization': self.token} - path = DISCORD_URL + "/guilds/" + str(self.server_id) + "/bans/" + str(user_id) - r = requests.delete(path, headers=custom_headers) - logger.debug("Received status code %s after deleting ban for user %s" % (r.status_code, user_id)) - r.raise_for_status() - - def generate_role(self): - custom_headers = {'accept':'application/json', 'authorization': self.token} - path = DISCORD_URL + "/guilds/" + str(self.server_id) + "/roles" - r = requests.post(path, headers=custom_headers) - logger.debug("Received status code %s after generating new role." % r.status_code) - r.raise_for_status() - return r.json() - - def edit_role(self, role_id, name, color=0, hoist=True, permissions=36785152): - custom_headers = {'content-type':'application/json', 'authorization': self.token} - data = { - 'color': color, - 'hoist': hoist, - 'name': name, - 'permissions': permissions, - } - path = DISCORD_URL + "/guilds/" + str(self.server_id) + "/roles/" + str(role_id) - r = requests.patch(path, headers=custom_headers, data=json.dumps(data)) - logger.debug("Received status code %s after editing role id %s" % (r.status_code, role_id)) - r.raise_for_status() - return r.json() - - def delete_role(self, role_id): - custom_headers = {'authorization': self.token} - path = DISCORD_URL + "/guilds/" + str(self.server_id) + "/roles/" + str(role_id) - r = requests.delete(path, headers=custom_headers) - r.raise_for_status() - - @staticmethod - def get_invite(invite_id): - custom_headers = {'accept': 'application/json'} - path = DISCORD_URL + "/invite/" + str(invite_id) - r = requests.get(path, headers=custom_headers) - r.raise_for_status() - return r.json() - - def accept_invite(self, invite_id): - custom_headers = {'accept': 'application/json', 'authorization': self.token} - path = DISCORD_URL + "/invite/" + str(invite_id) - r = requests.post(path, headers=custom_headers) - logger.debug("Received status code %s after accepting invite." % r.status_code) - r.raise_for_status() - return r.json() - - def create_invite(self, max_age=600, max_uses=1, temporary=True, xkcdpass=False): - custom_headers = {'authorization': self.token} - path = DISCORD_URL + "/channels/" + str(self.server_id) + "/invites" - data = { - 'max_age': max_age, - 'max_uses': max_uses, - 'temporary': temporary, - 'xkcdpass': xkcdpass, - } - r = requests.post(path, headers=custom_headers, data=json.dumps(data)) - logger.debug("Received status code %s after creating invite." % r.status_code) - r.raise_for_status() - return r.json() - - def delete_invite(self, invite_id): - custom_headers = {'authorization': self.token} - path = DISCORD_URL + "/invite/" + str(invite_id) - r = requests.delete(path, headers=custom_headers) - r.raise_for_status() - - def set_roles(self, user_id, role_ids): - custom_headers = {'authorization': self.token, 'content-type':'application/json'} - path = DISCORD_URL + "/guilds/" + str(self.server_id) + "/members/" + str(user_id) - data = { 'roles': role_ids } - r = requests.patch(path, headers=custom_headers, data=json.dumps(data)) - logger.debug("Received status code %s after setting roles of user %s to %s" % (r.status_code, user_id, role_ids)) - r.raise_for_status() - - @staticmethod - def register_user(server_id, username, invite_code, password, email): - custom_headers = {'content-type': 'application/json'} - data = { - 'fingerprint': None, - 'username': username, - 'invite': invite_code, - 'password': password, - 'email': email, - } - path = DISCORD_URL + "/auth/register" - r = requests.post(path, headers=custom_headers, data=json.dumps(data)) - r.raise_for_status() - - def kick_user(self, user_id): - custom_headers = {'authorization': self.token} - path = DISCORD_URL + "/guilds/" + str(self.server_id) + "/members/" + str(user_id) - r = requests.delete(path, headers=custom_headers) - r.raise_for_status() - - def get_members(self): - custom_headers = {'authorization': self.token, 'accept':'application/json'} - path = DISCORD_URL + "/guilds/" + str(self.server_id) + "/members" - r = requests.get(path, headers=custom_headers) - r.raise_for_status() - return r.json() - - def get_user_id(self, username): - all_members = self.get_members() - for member in all_members: - if member['user']['username'] == username: - return member['user']['id'] - raise KeyError('User not found on server: ' + username) - - def get_roles(self): - custom_headers = {'authorization': self.token, 'accept':'application/json'} - path = DISCORD_URL + "/guilds/" + str(self.server_id) + "/roles" - r = requests.get(path, headers=custom_headers) - logger.debug("Received status code %s after retrieving role list from server." % r.status_code) - r.raise_for_status() - return r.json() - - def get_group_id(self, group_name): - logger.debug("Determining role id for group name %s" % group_name) - all_roles = self.get_roles() - logger.debug("Retrieved role list for server: %s" % all_roles) - for role in all_roles: - logger.debug("Checking role %s" % role) - if role['name'] == group_name: - logger.debug("Found role matching name: %s" % role['id']) - return role['id'] - logger.debug("Role not found on server. Raising KeyError") - raise KeyError('Group not found on server: ' + group_name) - - @staticmethod - def get_token_by_user(email, password, user): - if DiscordAuthToken.objects.filter(email=email).exists(): - auth = DiscordAuthToken.objects.get(email=email) - if not auth.user == user: - raise ValueError("User mismatch while validating DiscordAuthToken for email %s - user %s, requesting user %s" % (email, auth.user, user)) - logger.debug("Discord auth token cached for supplied email starting with %s" % email[0:3]) - auth = DiscordAuthToken.objects.get(email=email, user=user) - if DiscordAPIManager.validate_token(auth.token): - logger.debug("Token still valid. Returning token starting with %s" % auth.token[0:5]) - return auth.token - else: - logger.debug("Token has expired. Deleting.") - auth.delete() - logger.debug("Generating auth token for email starting with %s user %s and password of length %s" % (email[0:3], user, len(password))) - data = { - "email" : email, - "password": password, - } - custom_headers = {'content-type':'application/json'} - path = DISCORD_URL + "/auth/login" - r = requests.post(path, headers=custom_headers, data=json.dumps(data)) - logger.debug("Received status code %s after generating auth token for custom user." % r.status_code) - r.raise_for_status() - token = r.json()['token'] - auth = DiscordAuthToken(email=email, token=token, user=user) - auth.save() - logger.debug("Created cached token for email starting with %s" % email[0:3]) - return token - - def get_profile(self): - custom_headers = {'accept': 'application/json', 'authorization': self.token} - path = DISCORD_URL + "/users/@me" - r = requests.get(path, headers=custom_headers) - logger.debug("Received status code %s after retrieving user profile with email %s" % (r.status_code, self.email[0:3])) - r.raise_for_status() - return r.json() - - @staticmethod - def get_user_profile(email, password, user): - token = DiscordAPIManager.get_token_by_user(email, password, user) - custom_headers = {'accept': 'application/json', 'authorization': token} - path = DISCORD_URL + "/users/@me" - r = requests.get(path, headers=custom_headers) - logger.debug("Received status code %s after retrieving user profile with email %s" % (r.status_code, email[0:3])) - r.raise_for_status() - return r.json() - - @staticmethod - def set_user_password(email, current_password, new_password, user): - profile = DiscordAPIManager.get_user_profile(email, current_password, user) - avatar = profile['avatar'] - username = profile['username'] - data = { - 'avatar': avatar, - 'username': username, - 'password': current_password, - 'new_password': new_password, - 'email': email, - } - path = DISCORD_URL + "/users/@me" - custom_headers = {'content-type':'application/json', 'authorization': DiscordAPIManager.get_token_by_user(email, current_password)} - r = requests.patch(path, headers=custom_headers, data=json.dumps(data)) - r.raise_for_status() - return r.json() - - @staticmethod - def set_user_avatar(email, current_password, user, avatar_url): - profile = DiscordAPIManager.get_user_profile(email, current_password, user) - avatar = "data:image/jpeg;base64," + base64.b64encode(urllib.urlopen(avatar_url).read()) - username = profile['username'] - data = { - 'avatar': avatar, - 'username': username, - 'password': current_password, - 'email': email - } - path = DISCORD_URL + "/users/@me" - custom_headers = {'content-type':'application/json', 'authorization': DiscordAPIManager.get_token_by_user(email, current_password, user)} - r = requests.patch(path, headers=custom_headers, data=json.dumps(data)) - r.raise_for_status() - return r.json() - - @staticmethod - def destroy_user(email, current_password): - data = { - 'avatar': None, - 'username': os.urandom(8).encode('hex'), - 'password': current_password, - 'email': os.urandom(8).encode('hex') + '@test.com', - } - path = DISCORD_URL + "/users/@me" - custom_headers = {'content-type':'application/json', 'authorization': DiscordAPIManager.get_token_by_user(email, current_password)} - r = requests.patch(path, headers=custom_headers, data=json.dumps(data)) - r.raise_for_status - return r.json() - - def check_if_user_banned(self, user_id): - bans = self.get_bans() - for b in bans: - if b['user']['id'] == str(user_id): - return True - return False - -class DiscordManager: - def __init__(self): - pass - - @staticmethod - def __sanatize_username(username): - clean = re.sub(r'[^\w]','_', username) - return clean - - @staticmethod - def __generate_random_pass(): - return os.urandom(8).encode('hex') - - @staticmethod - def update_groups(user_id, groups): - logger.debug("Updating groups for user_id %s: %s" % (user_id, groups)) - group_ids = [] - api = DiscordAPIManager(settings.DISCORD_SERVER_ID, settings.DISCORD_USER_EMAIL, settings.DISCORD_USER_PASSWORD) - if len(groups) == 0: - logger.debug("No groups provided - generating empty array of group ids.") - group_ids = [] - else: - for g in groups: - try: - logger.debug("Retrieving group id for group %s" % g) - group_id = api.get_group_id(g) - group_ids.append(group_id) - logger.debug("Got id %s" % group_id) - except: - logger.debug("Group id retrieval generated exception - generating new group on discord server.", exc_info=True) - group_ids.append(DiscordManager.create_group(g)) - logger.info("Setting discord groups for user %s to %s" % (user_id, group_ids)) - api.set_roles(user_id, group_ids) - - @staticmethod - def create_group(groupname): - logger.debug("Creating new group %s" % groupname) - api = DiscordAPIManager(settings.DISCORD_SERVER_ID, settings.DISCORD_USER_EMAIL, settings.DISCORD_USER_PASSWORD) - new_group = api.generate_role() - logger.debug("Created new role on server with id %s: %s" % (new_group['id'], new_group)) - named_group = api.edit_role(new_group['id'], groupname) - logger.debug("Renamed group id %s to %s" % (new_group['id'], groupname)) - logger.info("Created new group on discord server with name %s" % groupname) - return named_group['id'] - - @staticmethod - def lock_user(user_id): - try: - api = DiscordAPIManager(settings.DISCORD_SERVER_ID, settings.DISCORD_USER_EMAIL, settings.DISCORD_USER_PASSWORD) - api.ban_user(user_id) - return True - except: - return False - - @staticmethod - def unlock_user(user_id): - try: - api = DiscordAPIManager(settings.DISCORD_SERVER_ID, settings.DISCORD_USER_EMAIL, settings.DISCORD_USER_PASSWORD) - api.unban_user(user_id) - return True - except: - return False - - @staticmethod - def update_user_password(email, current_password, user): - new_password = DiscordManager.__generate_random_pass() - try: - profile = DiscordAPIManager.set_user_password(email, current_password, new_password, user) - return new_password - except: - return current_password - - @staticmethod - def update_user_avatar(email, password, user, char_id): - try: - char_url = EVE_IMAGE_SERVER + "/character/" + str(char_id) + "_256.jpg" - logger.debug("Character image URL for %s: %s" % (user, char_url)) - DiscordAPIManager.set_user_avatar(email, password, user, char_url) - return True - except: - return False - - @staticmethod - def add_user(email, password, user): - try: - logger.debug("Adding new user %s to discord with email %s and password of length %s" % (user, email[0:3], len(password))) - server_api = DiscordAPIManager(settings.DISCORD_SERVER_ID, settings.DISCORD_USER_EMAIL, settings.DISCORD_USER_PASSWORD) - user_api = DiscordAPIManager(settings.DISCORD_SERVER_ID, email, password, user=user) - profile = user_api.get_profile() - logger.debug("Got profile for user: %s" % profile) - user_id = profile['id'] - logger.debug("Determined user id: %s" % user_id) - - if server_api.check_if_user_banned(user_id): - logger.debug("User is currently banned. Unbanning %s" % user_id) - server_api.unban_user(user_id) - invite_code = server_api.create_invite()['code'] - logger.debug("Generated invite code beginning with %s" % invite_code[0:5]) - user_api.accept_invite(invite_code) - logger.info("Added user to discord server %s with id %s" % (settings.DISCORD_SERVER_ID, user_id)) - return user_id - except: - logger.exception("An unhandled exception has occured.") - return "" - - @staticmethod - def delete_user(user_id): - try: - logger.debug("Deleting user with id %s from discord server." % user_id) - api = DiscordAPIManager(settings.DISCORD_SERVER_ID, settings.DISCORD_USER_EMAIL, settings.DISCORD_USER_PASSWORD) - DiscordManager.update_groups(user_id, []) - api.ban_user(user_id) - logger.info("Deleted user with id %s from discord server id %s" % (user_id, settings.DISCORD_SERVER_ID)) - return True - except: - logger.exception("An unhandled exception has occured.") - return False - AUTH_URL = "https://discordapp.com/api/oauth2/authorize" TOKEN_URL = "https://discordapp.com/api/oauth2/token" -# kick, manage roles +# kick, manage roles, manage nicknames BOT_PERMISSIONS = 0x00000002 + 0x10000000 + 0x08000000 # get user ID, accept invite @@ -462,7 +28,16 @@ SCOPES = [ GROUP_CACHE_MAX_AGE = datetime.timedelta(minutes=30) + class DiscordOAuthManager: + def __init__(self): + pass + + @staticmethod + def _sanitize_groupname(name): + name = name.strip(' _') + return re.sub('[^\w.-]', '', name) + @staticmethod def generate_bot_add_url(): return AUTH_URL + '?client_id=' + settings.DISCORD_APP_ID + '&scope=bot&permissions=' + str(BOT_PERMISSIONS) @@ -506,11 +81,12 @@ class DiscordOAuthManager: @staticmethod def update_nickname(user_id, nickname): try: - custom_headers = {'content-type':'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN} - data = { 'nick': nickname, } + custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN} + data = {'nick': nickname, } path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id) r = requests.patch(path, headers=custom_headers, json=data) - logger.debug("Got status code %s after setting nickname for Discord user ID %s (%s)" % (r.status_code, user_id, nickname)) + logger.debug("Got status code %s after setting nickname for Discord user ID %s (%s)" % ( + r.status_code, user_id, nickname)) if r.status_code == 404: logger.warn("Discord user ID %s could not be found in server." % user_id) return True @@ -584,7 +160,7 @@ class DiscordOAuthManager: @staticmethod def __generate_role(): - custom_headers = {'accept':'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN} + custom_headers = {'accept': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN} path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/roles" r = requests.post(path, headers=custom_headers) logger.debug("Received status code %s after generating new role." % r.status_code) @@ -593,11 +169,11 @@ class DiscordOAuthManager: @staticmethod def __edit_role(role_id, name, color=0, hoist=True, permissions=36785152): - custom_headers = {'content-type':'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN} + custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN} data = { 'color': color, 'hoist': hoist, - 'name': name, + 'name': name, 'permissions': permissions, } path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/roles/" + str(role_id) @@ -609,13 +185,13 @@ class DiscordOAuthManager: @staticmethod def __create_group(name): role = DiscordOAuthManager.__generate_role() - new_role = DiscordOAuthManager.__edit_role(role['id'], name) + DiscordOAuthManager.__edit_role(role['id'], name) DiscordOAuthManager.__update_group_cache() @staticmethod def update_groups(user_id, groups): - custom_headers = {'content-type':'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN} - group_ids = [DiscordOAuthManager.__group_name_to_id(g) for g in groups] + custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN} + group_ids = [DiscordOAuthManager.__group_name_to_id(DiscordOAuthManager._sanitize_groupname(g)) for g in groups] path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id) data = {'roles': group_ids} r = requests.patch(path, headers=custom_headers, json=data) diff --git a/services/managers/discourse_manager.py b/services/managers/discourse_manager.py index 047963fa..779a315f 100644 --- a/services/managers/discourse_manager.py +++ b/services/managers/discourse_manager.py @@ -1,8 +1,10 @@ +from __future__ import unicode_literals import logging import requests import os import datetime import json +import re from django.conf import settings from django.utils import timezone from services.models import GroupCache @@ -113,7 +115,11 @@ ENDPOINTS = { }, } + class DiscourseManager: + def __init__(self): + pass + GROUP_CACHE_MAX_AGE = datetime.timedelta(minutes=30) REVOKED_EMAIL = 'revoked@' + settings.DOMAIN SUSPEND_DAYS = 99999 @@ -136,7 +142,7 @@ class DiscourseManager: if arg in kwargs: data[arg] = kwargs[arg] for arg in kwargs: - if not arg in endpoint['args']['required'] and not arg in endpoint['args']['optional']: + if arg not in endpoint['args']['required'] and arg not in endpoint['args']['optional']: logger.warn("Received unrecognized kwarg %s for endpoint %s" % (arg, endpoint)) r = endpoint['method'](settings.DISCOURSE_URL + path, params=params, json=data) out = r.text @@ -218,10 +224,10 @@ class DiscourseManager: @staticmethod def __generate_group_dict(names): - dict = {} + group_dict = {} for name in names: - dict[name] = DiscourseManager.__group_name_to_id(name) - return dict + group_dict[name] = DiscourseManager.__group_name_to_id(name) + return group_dict @staticmethod def __get_user_groups(username): @@ -271,7 +277,8 @@ class DiscourseManager: def __suspend_user(username): id = DiscourseManager.__user_name_to_id(username) endpoint = ENDPOINTS['users']['suspend'] - return DiscourseManager.__exc(endpoint, id, duration=DiscourseManager.SUSPEND_DAYS, reason=DiscourseManager.SUSPEND_REASON) + return DiscourseManager.__exc(endpoint, id, duration=DiscourseManager.SUSPEND_DAYS, + reason=DiscourseManager.SUSPEND_REASON) @staticmethod def __unsuspend(username): @@ -287,9 +294,15 @@ class DiscourseManager: @staticmethod def _sanatize_username(username): sanatized = username.replace(" ", "_") + sanatized = sanatized.strip(' _') sanatized = sanatized.replace("'", "") return sanatized + @staticmethod + def _sanitize_groupname(name): + name = name.strip(' _') + return re.sub('[^\w]', '', name) + @staticmethod def add_user(username, email): logger.debug("Adding new discourse user %s" % username) @@ -306,7 +319,7 @@ class DiscourseManager: return safe_username, password except: logger.exception("Failed to add new discourse user %s" % username) - return "","" + return "", "" @staticmethod def delete_user(username): @@ -323,15 +336,16 @@ class DiscourseManager: def update_groups(username, raw_groups): groups = [] for g in raw_groups: - groups.append(g[:20]) + groups.append(DiscourseManager._sanitize_groupname(g[:20])) logger.debug("Updating discourse user %s groups to %s" % (username, groups)) group_dict = DiscourseManager.__generate_group_dict(groups) - inv_group_dict = {v:k for k,v in group_dict.items()} + inv_group_dict = {v: k for k, v in group_dict.items()} user_groups = DiscourseManager.__get_user_groups(username) add_groups = [group_dict[x] for x in group_dict if not group_dict[x] in user_groups] rem_groups = [x for x in user_groups if not inv_group_dict[x] in groups] if add_groups or rem_groups: - logger.info("Updating discourse user %s groups: adding %s, removing %s" % (username, add_groups, rem_groups)) + logger.info( + "Updating discourse user %s groups: adding %s, removing %s" % (username, add_groups, rem_groups)) for g in add_groups: DiscourseManager.__add_user_to_group(g, username) for g in rem_groups: diff --git a/services/managers/eve_api_manager.py b/services/managers/eve_api_manager.py index 171b934c..7f86021f 100644 --- a/services/managers/eve_api_manager.py +++ b/services/managers/eve_api_manager.py @@ -1,20 +1,48 @@ +from __future__ import unicode_literals import evelink.api import evelink.char import evelink.eve - +from authentication.states import MEMBER_STATE, BLUE_STATE +from authentication.models import AuthServicesInfo +from eveonline.models import EveCharacter from django.conf import settings import logging logger = logging.getLogger(__name__) -class EveApiManager(): + +class EveApiManager: def __init__(self): pass + class ApiValidationError(Exception): + def __init__(self, msg, api_id): + self.msg = msg + self.api_id = api_id + + def __str__(self): + return self.msg + + class ApiMaskValidationError(ApiValidationError): + def __init__(self, required_mask, api_mask, api_id): + msg = 'Insufficient API mask provided. Required: %s Got: %s' % (required_mask, api_mask) + self.required_mask = required_mask + self.api_mask = api_mask + super(EveApiManager.ApiMaskValidationError, self).__init__(msg, api_id) + + class ApiAccountValidationError(ApiValidationError): + def __init__(self, api_id): + msg = 'Insufficient API access provided. Full account access is required, got character restricted.' + super(EveApiManager.ApiAccountValidationError, self).__init__(msg, api_id) + + class ApiInvalidError(ApiValidationError): + def __init__(self, api_id): + msg = 'Key is invalid.' + super(EveApiManager.ApiInvalidError, self).__init__(msg, api_id) + @staticmethod def get_characters_from_api(api_id, api_key): - chars = [] logger.debug("Getting characters from api id %s" % api_id) api = evelink.api.API(api_key=(api_id, api_key)) # Should get characters @@ -26,7 +54,6 @@ class EveApiManager(): @staticmethod def get_corporation_ticker_from_id(corp_id): logger.debug("Getting ticker for corp id %s" % corp_id) - ticker = "" api = evelink.api.API() corp = evelink.corp.Corp(api) response = corp.corporation_sheet(corp_id) @@ -37,7 +64,6 @@ class EveApiManager(): @staticmethod def get_alliance_information(alliance_id): - results = {} logger.debug("Getting info for alliance with id %s" % alliance_id) api = evelink.api.API() eve = evelink.eve.EVE(api=api) @@ -49,7 +75,6 @@ class EveApiManager(): @staticmethod def get_corporation_information(corp_id): logger.debug("Getting info for corp with id %s" % corp_id) - results = {} api = evelink.api.API() corp = evelink.corp.Corp(api=api) corpinfo = corp.corporation_sheet(corp_id=int(corp_id)) @@ -57,6 +82,12 @@ class EveApiManager(): logger.debug("Got corp info %s" % results) return results + @staticmethod + def get_api_info(api_id, api_key): + api = evelink.api.API(api_key=(api_id, api_key)) + account = evelink.account.Account(api=api) + return account.key_info()[0] + @staticmethod def check_api_is_type_account(api_id, api_key): logger.debug("Checking if api id %s is account." % api_id) @@ -83,7 +114,7 @@ class EveApiManager(): info = account.key_info() logger.debug("API has mask %s, required is %s" % (info[0]['access_mask'], settings.BLUE_API_MASK)) return info[0]['access_mask'] & int(settings.BLUE_API_MASK) == int(settings.BLUE_API_MASK) - + @staticmethod def get_api_info(api_id, api_key): logger.debug("Getting api info for key id %s" % api_id) @@ -98,7 +129,7 @@ class EveApiManager(): logger.debug("Checking if api id %s is valid." % api_id) api = evelink.api.API(api_key=(api_id, api_key)) account = evelink.account.Account(api=api) - info = account.key_info() + account.key_info() logger.info("Verified api id %s is still valid." % api_id) return True @@ -108,10 +139,10 @@ class EveApiManager(): try: api = evelink.api.API() server = evelink.server.Server(api=api) - info = server.server_status() + server.server_status() logger.info("Verified API server is online and reachable.") return True - except evelink.api.APIError as error: + except evelink.api.APIError: logger.exception("APIError occured while trying to query api server. Possibly offline?") logger.warn("Unable to reach API server.") @@ -124,7 +155,7 @@ class EveApiManager(): api = evelink.api.API() corp = evelink.corp.Corp(api=api) corpinfo = corp.corporation_sheet(corp_id=int(corp_id)) - results = corpinfo[0] + assert corpinfo[0] logger.debug("Confirmed id %s is a corp." % corp_id) return True except evelink.api.APIError as error: @@ -160,11 +191,10 @@ class EveApiManager(): results = membertracking.result logger.debug("Got corp membertracking from settings: %s" % results) return results - except evelink.api.APIError as error: + except evelink.api.APIError: logger.exception("Unhandled APIError occured.") return {} - @staticmethod def check_if_id_is_alliance(alliance_id): logger.debug("Checking if id %s is an alliance." % alliance_id) @@ -176,8 +206,9 @@ class EveApiManager(): if results: logger.debug("Confirmed id %s is an alliance." % alliance_id) return True - except evelink.api.APIError as error: - logger.exception("APIError occured while checking if id %s is an alliance. Possibly not alliance?" % alliance_id) + except evelink.api.APIError: + logger.exception( + "APIError occured while checking if id %s is an alliance. Possibly not alliance?" % alliance_id) except KeyError: logger.debug("Alliance with id %s not found in active alliance list." % alliance_id) return False @@ -194,8 +225,10 @@ class EveApiManager(): if results: logger.debug("Confirmed id %s is a character." % character_id) return True - except evelink.api.APIError as error: - logger.debug("APIError occured while checking if id %s is a character. Possibly not character?" % character_id, exc_info=True) + except evelink.api.APIError: + logger.debug( + "APIError occured while checking if id %s is a character. Possibly not character?" % character_id, + exc_info=True) logger.debug("Unable to verify id %s is a character." % character_id) return False @@ -213,15 +246,16 @@ class EveApiManager(): else: logger.debug("Verified alliance id %s does not exist." % alliance_id) return False - except evelink.api.APIError as error: + except evelink.api.APIError: logger.exception("Unhandled APIError occured.") return False - except ValueError as error: - #attempts to catch error resulting from checking alliance_of nonetype models + except ValueError: + # attempts to catch error resulting from checking alliance_of nonetype models logger.exception("Unhandled ValueError occured. Possible nonetype alliance model.") return False - logger.warn("Exception prevented verification of alliance id %s existance. Assuming false." % alliance_id) - return False + except: + logger.warn("Exception prevented verification of alliance id %s existance. Assuming false." % alliance_id) + return False @staticmethod def check_if_corp_exists(corp_id): @@ -231,17 +265,20 @@ class EveApiManager(): corp = evelink.corp.Corp(api=api) corpinfo = corp.corporation_sheet(corp_id=corp_id) if corpinfo[0]['members']['current'] > 0: - logger.debug("Verified corp id %s exists with member count %s" % (corp_id, corpinfo[0]['members']['current'])) + logger.debug( + "Verified corp id %s exists with member count %s" % (corp_id, corpinfo[0]['members']['current'])) return True else: - logger.debug("Verified corp id %s has closed. Member count %s" % (corp_id, corpinfo[0]['members']['current'])) + logger.debug( + "Verified corp id %s has closed. Member count %s" % (corp_id, corpinfo[0]['members']['current'])) return False - except evelink.api.APIError as error: - #could be smart and check for error code523 to verify error due to no corp instead of catch-all + except evelink.api.APIError: + # could be smart and check for error code523 to verify error due to no corp instead of catch-all logger.exception("Unhandled APIError occured.") return False - logger.warn("Exception prevented verification of corp id %s existance. Assuming false." % corp_id) - return False + except: + logger.warn("Exception prevented verification of corp id %s existance. Assuming false." % corp_id) + return False @staticmethod def validate_member_api(api_id, api_key): @@ -249,7 +286,7 @@ class EveApiManager(): if EveApiManager.check_api_is_type_account(api_id, api_key) is False: logger.info("Api id %s is not type account as required for members - failed validation." % api_id) return False - + if EveApiManager.check_api_is_full(api_id, api_key) is False: logger.info("Api id %s does not meet member access mask requirements - failed validation." % api_id) return False @@ -265,3 +302,40 @@ class EveApiManager(): logger.info("Api id %s does not meet minimum blue access mask requirements - failed validation." % api_id) return False return True + + @staticmethod + def validate_api(api_id, api_key, user): + try: + info = EveApiManager.get_api_info(api_id, api_key).result + chars = EveApiManager.get_characters_from_api(api_id, api_key).result + except evelink.api.APIError as e: + if int(e.code) in [221, 222]: + raise e + raise EveApiManager.ApiInvalidError(api_id) + except Exception: + raise EveApiManager.ApiInvalidError(api_id) + auth, c = AuthServicesInfo.objects.get_or_create(user=user) + states = [auth.state] + from authentication.tasks import determine_membership_by_character # circular import issue + for char in chars: + evechar = EveCharacter() + evechar.character_name = chars[char]['name'] + evechar.corporation_id = chars[char]['corp']['id'] + evechar.alliance_id = chars[char]['alliance']['id'] + states.append(determine_membership_by_character(evechar)) + if MEMBER_STATE not in states and BLUE_STATE not in states: + # default to requiring member keys for applications + states.append(MEMBER_STATE) + logger.debug('Checking API %s for states %s' % (api_id, states)) + for state in states: + if (state == MEMBER_STATE and settings.MEMBER_API_ACCOUNT) or ( + state == BLUE_STATE and settings.BLUE_API_ACCOUNT): + if info['type'] != 'account': + raise EveApiManager.ApiAccountValidationError(api_id) + if state == MEMBER_STATE: + if int(info['access_mask']) & int(settings.MEMBER_API_MASK) != int(settings.MEMBER_API_MASK): + raise EveApiManager.ApiMaskValidationError(settings.MEMBER_API_MASK, info['access_mask'], api_id) + elif state == BLUE_STATE: + if int(info['access_mask']) & int(settings.BLUE_API_MASK) != int(settings.BLUE_API_MASK): + raise EveApiManager.ApiMaskValidationError(settings.BLUE_API_MASK, info['access_mask'], api_id) + return True diff --git a/services/managers/evewho_manager.py b/services/managers/evewho_manager.py index 257b47d8..ee7407e2 100644 --- a/services/managers/evewho_manager.py +++ b/services/managers/evewho_manager.py @@ -1,13 +1,9 @@ -from django.conf import settings - -import logging +from __future__ import unicode_literals import requests -#import requests_cache import json -#requests_cache.install_cache("{}/evewho".format(settings.EVEWHO_CACHE_DIR), backend="sqlite", expire_after=3600) -class EveWhoManager(): +class EveWhoManager: def __init__(self): pass @@ -18,11 +14,11 @@ class EveWhoManager(): data = json.loads(jsondata.decode()) members = {} - page_count=0 + page_count = 0 while len(data["characters"]): for row in data["characters"]: - members[int(row["character_id"])] = {"name":row["name"], "id":int(row["character_id"])} - page_count=page_count+1 + members[int(row["character_id"])] = {"name": row["name"], "id": int(row["character_id"])} + page_count += 1 jsondata = requests.get(url + "&page=%i" % page_count).content data = json.loads(jsondata.decode()) diff --git a/services/managers/fleetup_manager.py b/services/managers/fleetup_manager.py index 9209c916..be6f5cb0 100644 --- a/services/managers/fleetup_manager.py +++ b/services/managers/fleetup_manager.py @@ -1,5 +1,5 @@ +from __future__ import unicode_literals from django.conf import settings -from django.http import HttpResponse from datetime import datetime import logging @@ -13,43 +13,45 @@ userid = settings.FLEETUP_USER_ID apiid = settings.FLEETUP_API_ID groupid = settings.FLEETUP_GROUP_ID -class FleetUpManager(): + +class FleetUpManager: def __init__(self): pass @staticmethod def get_fleetup_members(): - url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(apiid) + "/GroupCharacters/" + str(groupid) + "" + url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str( + apiid) + "/GroupCharacters/" + str(groupid) + "" try: jsondata = requests.get(url).content - fmembers=json.loads(jsondata.decode()) - return {row["UserId"]:{"user_id":row["UserId"], - "char_name":row["EveCharName"], - "char_id":row["EveCharId"], - "corporation":row["Corporation"]} for row in fmembers["Data"]} + fmembers = json.loads(jsondata.decode()) + return {row["UserId"]: {"user_id": row["UserId"], + "char_name": row["EveCharName"], + "char_id": row["EveCharId"], + "corporation": row["Corporation"]} for row in fmembers["Data"]} except requests.exceptions.ConnectionError: logger.warn("Can't connect to Fleet-Up API, is it offline?!") except (ValueError, UnicodeDecodeError): logger.debug("No fleetup members retrieved.") return {} - @staticmethod def get_fleetup_operations(): - url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(apiid) + "/Operations/" + str(groupid) + "" + url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str( + apiid) + "/Operations/" + str(groupid) + "" try: jsondata = requests.get(url).content - foperations=json.loads(jsondata.decode()) - return {row["StartString"]:{"subject":row["Subject"], - "start": (datetime.strptime(row["StartString"], "%Y-%m-%d %H:%M:%S")), - "end": (datetime.strptime(row["EndString"], "%Y-%m-%d %H:%M:%S")), - "operation_id":row["OperationId"], - "location":row["Location"], - "location_info":row["LocationInfo"], - "details":row["Details"], - "url":row["Url"], - "doctrine":row["Doctrines"], - "organizer":row["Organizer"]} for row in foperations["Data"]} + foperations = json.loads(jsondata.decode()) + return {row["StartString"]: {"subject": row["Subject"], + "start": (datetime.strptime(row["StartString"], "%Y-%m-%d %H:%M:%S")), + "end": (datetime.strptime(row["EndString"], "%Y-%m-%d %H:%M:%S")), + "operation_id": row["OperationId"], + "location": row["Location"], + "location_info": row["LocationInfo"], + "details": row["Details"], + "url": row["Url"], + "doctrine": row["Doctrines"], + "organizer": row["Organizer"]} for row in foperations["Data"]} except requests.exceptions.ConnectionError: logger.warn("Can't connect to Fleet-Up API, is it offline?!") except (ValueError, UnicodeDecodeError): @@ -58,18 +60,19 @@ class FleetUpManager(): @staticmethod def get_fleetup_timers(): - url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(apiid) + "/Timers/" + str(groupid) + "" + url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str( + apiid) + "/Timers/" + str(groupid) + "" try: jsondata = requests.get(url).content - ftimers=json.loads(jsondata.decode()) - return {row["ExpiresString"]:{"solarsystem":row["SolarSystem"], - "planet":row["Planet"], - "moon":row["Moon"], - "owner":row["Owner"], - "type":row["Type"], - "timer_type":row["TimerType"], - "expires": (datetime.strptime(row["ExpiresString"], "%Y-%m-%d %H:%M:%S")), - "notes":row["Notes"]} for row in ftimers["Data"]} + ftimers = json.loads(jsondata.decode()) + return {row["ExpiresString"]: {"solarsystem": row["SolarSystem"], + "planet": row["Planet"], + "moon": row["Moon"], + "owner": row["Owner"], + "type": row["Type"], + "timer_type": row["TimerType"], + "expires": (datetime.strptime(row["ExpiresString"], "%Y-%m-%d %H:%M:%S")), + "notes": row["Notes"]} for row in ftimers["Data"]} except requests.exceptions.ConnectionError: logger.warn("Can't connect to Fleet-Up API, is it offline?!") except (ValueError, UnicodeDecodeError): @@ -78,45 +81,50 @@ class FleetUpManager(): @staticmethod def get_fleetup_doctrines(): - url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(apiid) + "/Doctrines/" + str(groupid) + "" + url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str( + apiid) + "/Doctrines/" + str(groupid) + "" try: jsondata = requests.get(url).content - fdoctrines=json.loads(jsondata.decode()) - return {"fleetup_doctrines":fdoctrines["Data"]} + fdoctrines = json.loads(jsondata.decode()) + return {"fleetup_doctrines": fdoctrines["Data"]} except requests.exceptions.ConnectionError: logger.warn("Can't connect to Fleet-Up API, is it offline?!") except (ValueError, UnicodeDecodeError): logger.debug("No fleetup doctrines retrieved.") - return {"fleetup_doctrines":[]} + return {"fleetup_doctrines": []} @staticmethod def get_fleetup_doctrine(doctrinenumber): - url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(apiid) + "/DoctrineFittings/%s" % doctrinenumber + url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str( + apiid) + "/DoctrineFittings/%s" % doctrinenumber try: jsondata = requests.get(url).content - fdoctrine=json.loads(jsondata.decode()) - return {"fitting_doctrine":fdoctrine} + fdoctrine = json.loads(jsondata.decode()) + return {"fitting_doctrine": fdoctrine} except requests.exceptions.ConnectionError: logger.warn("Can't connect to Fleet-Up API, is it offline?!") except (ValueError, UnicodeDecodeError): logger.warn("Fleetup doctrine number %s not found" % doctrinenumber) - return {"fitting_doctrine":{}} + return {"fitting_doctrine": {}} @staticmethod def get_fleetup_fittings(): - url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(apiid) + "/Fittings/" + str(groupid) + "" + url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str( + apiid) + "/Fittings/" + str(groupid) + "" try: jsondata = requests.get(url).content - ffittings=json.loads(jsondata.decode()) - return {row["FittingId"]:{"fitting_id":row["FittingId"], - "name":row["Name"], - "icon_id":row["EveTypeId"], - "hull":row["HullType"], - "shiptype":row["ShipType"], - "estimated":row["EstPrice"], - "faction":row["Faction"], - "categories":row["Categories"], - "last_update":(datetime.strptime(row["LastUpdatedString"], "%Y-%m-%d %H:%M:%S"))} for row in ffittings["Data"]} + ffittings = json.loads(jsondata.decode()) + return {row["FittingId"]: {"fitting_id": row["FittingId"], + "name": row["Name"], + "icon_id": row["EveTypeId"], + "hull": row["HullType"], + "shiptype": row["ShipType"], + "estimated": row["EstPrice"], + "faction": row["Faction"], + "categories": row["Categories"], + "last_update": ( + datetime.strptime(row["LastUpdatedString"], "%Y-%m-%d %H:%M:%S"))} for row in + ffittings["Data"]} except requests.exceptions.ConnectionError: logger.warn("Can't connect to Fleet-Up API, is it offline?!") except (ValueError, UnicodeDecodeError): @@ -125,25 +133,27 @@ class FleetUpManager(): @staticmethod def get_fleetup_fitting(fittingnumber): - url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(apiid) + "/Fitting/%s" % fittingnumber + url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str( + apiid) + "/Fitting/%s" % fittingnumber try: jsondata = requests.get(url).content - ffitting=json.loads(jsondata.decode()) - return {"fitting_data":ffitting["Data"]} + ffitting = json.loads(jsondata.decode()) + return {"fitting_data": ffitting["Data"]} except requests.exceptions.ConnectionError: logger.warn("Can't connect to Fleet-Up API, is it offline?!") except (ValueError, UnicodeDecodeError): logger.warn("Fleetup fitting number %s not found" % fittingnumber) except KeyError: logger.warn("Failed to retrieve fleetup fitting number %s" % fittingnumber) - return {"fitting_data":{}} + return {"fitting_data": {}} @staticmethod def get_fleetup_doctrineid(fittingnumber): - url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(apiid) + "/Fitting/%s" % fittingnumber + url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str( + apiid) + "/Fitting/%s" % fittingnumber try: jsondata = requests.get(url).content - fdoctrineid=json.loads(jsondata.decode()) + fdoctrineid = json.loads(jsondata.decode()) return fdoctrineid['Data']['Doctrines'][0]['DoctrineId'] except requests.exceptions.ConnectionError: logger.warn("Can't connect to Fleet-Up API, is it offline?!") @@ -155,13 +165,14 @@ class FleetUpManager(): @staticmethod def get_fleetup_fitting_eft(fittingnumber): - url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str(apiid) + "/Fitting/%s/eft" % fittingnumber + url = "http://api.fleet-up.com/Api.svc/" + str(appkey) + "/" + str(userid) + "/" + str( + apiid) + "/Fitting/%s/eft" % fittingnumber try: jsondata = requests.get(url).content - ffittingeft=json.loads(jsondata.decode()) - return {"fitting_eft":ffittingeft["Data"]["FittingData"]} + ffittingeft = json.loads(jsondata.decode()) + return {"fitting_eft": ffittingeft["Data"]["FittingData"]} except requests.exceptions.ConnectionError: logger.warn("Can't connect to Fleet-Up API, is it offline?!") except (ValueError, UnicodeDecodeError): logger.warn("Fleetup fitting eft not found for fitting number %s" % fittingnumber) - return {"fitting_eft":{}} + return {"fitting_eft": {}} diff --git a/services/managers/ipboard_manager.py b/services/managers/ipboard_manager.py index f966d0f5..4f6e5124 100755 --- a/services/managers/ipboard_manager.py +++ b/services/managers/ipboard_manager.py @@ -1,6 +1,13 @@ +from __future__ import unicode_literals import os -import xmlrpclib +import re from hashlib import md5 +try: + from xmlrpclib import Server +except ImportError: + # python 3 + from xmlrpc import server as Server + from django.conf import settings @@ -8,6 +15,7 @@ import logging logger = logging.getLogger(__name__) + class IPBoardManager: def __init__(self): pass @@ -21,17 +29,21 @@ class IPBoardManager: def __generate_random_pass(): return os.urandom(8).encode('hex') + @staticmethod + def _sanitize_groupname(name): + name = name.strip(' _') + return re.sub('[^\w.-]', '', name) + @staticmethod def exec_xmlrpc(func, **kwargs): """ Send a XMLRPC request """ try: - server = xmlrpclib.Server(settings.IPBOARD_ENDPOINT, verbose=False) + server = Server(settings.IPBOARD_ENDPOINT, verbose=False) params = {} for i in kwargs: params[i] = kwargs[i] params['api_key'] = settings.IPBOARD_APIKEY params['api_module'] = settings.IPBOARD_APIMODULE - print params return getattr(server, func)(params) except: @@ -44,22 +56,22 @@ class IPBoardManager: logger.debug("Adding user to IPBoard with username %s" % sanatized) plain_password = IPBoardManager.__generate_random_pass() password = md5(plain_password).hexdigest() - ret = IPBoardManager.exec_xmlrpc('createUser', username=sanatized, email=str(email), display_name=sanatized, - md5_passwordHash=password) + IPBoardManager.exec_xmlrpc('createUser', username=sanatized, email=str(email), display_name=sanatized, + md5_passwordHash=password) logger.info("Added IPBoard user with username %s" % sanatized) return sanatized, plain_password @staticmethod def delete_user(username): """ Delete user """ - ret = IPBoardManager.exec_xmlrpc('deleteUser', username=username) + IPBoardManager.exec_xmlrpc('deleteUser', username=username) logger.info("Deleted IPBoard user with username %s" % username) return username @staticmethod def disable_user(username): """ Disable user """ - ret = IPBoardManager.exec_xmlrpc('disableUser', username=username) + IPBoardManager.exec_xmlrpc('disableUser', username=username) logger.info("Disabled IPBoard user with username %s" % username) return username @@ -67,8 +79,9 @@ class IPBoardManager: def update_user(username, email, password): """ Add user to service """ password = md5(password).hexdigest() - logger.debug("Updating IPBoard username %s with email %s and password hash starting with %s" % (username, email, password[0:5])) - ret = IPBoardManager.exec_xmlrpc('updateUser', username=username, email=email, md5_passwordHash=password) + logger.debug("Updating IPBoard username %s with email %s and password hash starting with %s" % ( + username, email, password[0:5])) + IPBoardManager.exec_xmlrpc('updateUser', username=username, email=email, md5_passwordHash=password) logger.info("Updated IPBoard user with username %s" % username) return username @@ -111,7 +124,6 @@ class IPBoardManager: @staticmethod def help_me(): - "Random help me" ret = IPBoardManager.exec_xmlrpc('helpMe') return ret @@ -120,13 +132,13 @@ class IPBoardManager: logger.debug("Updating IPBoard user %s with groups %s" % (username, groups)) forum_groups = IPBoardManager.get_all_groups() user_groups = set(IPBoardManager.get_user_groups(username)) - act_groups = set([g.replace(' ', '-') for g in groups]) + act_groups = set([IPBoardManager._sanitize_groupname(g) for g in groups]) addgroups = act_groups - user_groups remgroups = user_groups - act_groups logger.info("Updating IPBoard groups for user %s - adding %s, removing %s" % (username, addgroups, remgroups)) for g in addgroups: - if not g in forum_groups: + if g not in forum_groups: IPBoardManager.add_group(g) logger.debug("Adding user %s to IPBoard group %s" % (username, g)) IPBoardManager.add_user_to_group(username, g) diff --git a/services/managers/ips4_manager.py b/services/managers/ips4_manager.py index ad0e9eed..1fd59b5c 100644 --- a/services/managers/ips4_manager.py +++ b/services/managers/ips4_manager.py @@ -1,27 +1,21 @@ +from __future__ import unicode_literals import logging -from django.conf import settings -import requests import os from django.db import connections from passlib.hash import bcrypt -from django.utils import timezone - logger = logging.getLogger(__name__) -class Ips4Manager: +class Ips4Manager: SQL_ADD_USER = r"INSERT INTO core_members (name, email, members_pass_hash, members_pass_salt, " \ r"member_group_id) VALUES (%s, %s, %s, %s, %s)" SQL_GET_ID = r"SELECT member_id FROM core_members WHERE name = %s" SQL_UPDATE_PASSWORD = r"UPDATE core_members SET members_pass_hash = %s, members_pass_salt = %s WHERE name = %s" SQL_DEL_USER = r"DELETE FROM core_members WHERE member_id = %s" - - MEMBER_GROUP_ID = 3 - @staticmethod def add_user(username, email): logger.debug("Adding new IPS4 user %s" % username) @@ -30,7 +24,6 @@ class Ips4Manager: hash_result = hash rounds_striped = hash_result.strip('$2a$13$') salt = rounds_striped[:22] - joined_date = timezone.now group = Ips4Manager.MEMBER_GROUP_ID cursor = connections['ips4'].cursor() cursor.execute(Ips4Manager.SQL_ADD_USER, [username, email, hash, salt, group]) @@ -53,7 +46,6 @@ class Ips4Manager: def __generate_random_pass(): return os.urandom(8).encode('hex') - @staticmethod def delete_user(id): logger.debug("Deleting IPS4 user id %s" % id) @@ -107,4 +99,4 @@ class Ips4Manager: return plain_password else: logger.error("Unable to update ips4 user %s password" % username) - return "" \ No newline at end of file + return "" diff --git a/services/managers/market_manager.py b/services/managers/market_manager.py index c397c336..c1958fbb 100644 --- a/services/managers/market_manager.py +++ b/services/managers/market_manager.py @@ -1,18 +1,21 @@ +from __future__ import unicode_literals import logging -from django.conf import settings -import requests import os from django.db import connections from passlib.hash import bcrypt -## requires yum install libffi-devel and pip install bcrypt + +# requires yum install libffi-devel and pip install bcrypt logger = logging.getLogger(__name__) -class marketManager: - SQL_ADD_USER = r"INSERT INTO fos_user (username, username_canonical, email, email_canonical, enabled, salt, password," \ - r"locked, expired, roles, credentials_expired, characterid, characterName)" \ +class marketManager: + def __init__(self): + pass + + SQL_ADD_USER = r"INSERT INTO fos_user (username, username_canonical, email, email_canonical, enabled, salt," \ + r"password, locked, expired, roles, credentials_expired, characterid, characterName)" \ r"VALUES (%s, %s, %s, %s, 1,%s, %s, 0, 0, 'a:0:{}', 0, %s, %s) " SQL_GET_USER_ID = r"SELECT id FROM fos_user WHERE username = %s" SQL_DISABLE_USER = r"UPDATE fos_user SET enabled = '0' WHERE username = %s" @@ -22,7 +25,6 @@ class marketManager: SQL_CHECK_USERNAME = r"SELECT username FROM fos_user WHERE username = %s" SQL_UPDATE_USER = r"UPDATE fos_user SET password = %s, salt = %s, enabled = '1' WHERE username = %s" - @staticmethod def __santatize_username(username): sanatized = username.replace(" ", "_") @@ -56,7 +58,6 @@ class marketManager: logger.debug("User %s email address not found on alliance market" % username) return False - @staticmethod def add_user(username, email, characterid, charactername): logger.debug("Adding new market user %s" % username) @@ -66,8 +67,8 @@ class marketManager: rounds_striped = hash_result.strip('$2a$13$') salt = rounds_striped[:22] username_clean = marketManager.__santatize_username(username) - if marketManager.check_username(username)== False: - if marketManager.check_user_email(username, email) == False: + if not marketManager.check_username(username): + if not marketManager.check_user_email(username, email): try: logger.debug("Adding user %s to alliance market" % username) cursor = connections['market'].cursor() diff --git a/services/managers/mumble_manager.py b/services/managers/mumble_manager.py index a1ef9b5f..b3e12ff4 100755 --- a/services/managers/mumble_manager.py +++ b/services/managers/mumble_manager.py @@ -1,10 +1,6 @@ +from __future__ import unicode_literals import os import hashlib -import sys - -import django -from django.db import connections -from django.conf import settings from services.models import MumbleUser @@ -12,7 +8,10 @@ import logging logger = logging.getLogger(__name__) + class MumbleManager: + def __init__(self): + pass @staticmethod def __santatize_username(username): @@ -41,10 +40,11 @@ class MumbleManager: username_clean = MumbleManager.__santatize_username(MumbleManager.__generate_username(username, corp_ticker)) password = MumbleManager.__generate_random_pass() pwhash = MumbleManager._gen_pwhash(password) - logger.debug("Proceeding with mumble user creation: clean username %s, pwhash starts with %s" % (username_clean, pwhash[0:5])) + logger.debug("Proceeding with mumble user creation: clean username %s, pwhash starts with %s" % ( + username_clean, pwhash[0:5])) if MumbleUser.objects.filter(username=username_clean).exists() is False: logger.info("Creating mumble user %s" % username_clean) - model = MumbleUser.objects.create(username=username_clean, pwhash=pwhash) + MumbleUser.objects.create(username=username_clean, pwhash=pwhash) return username_clean, password else: logger.warn("Mumble user %s already exists. Updating password") @@ -57,13 +57,15 @@ class MumbleManager: @staticmethod def create_blue_user(corp_ticker, username): logger.debug("Creating mumble blue user with username %s and ticker %s" % (username, corp_ticker)) - username_clean = MumbleManager.__santatize_username(MumbleManager.__generate_username_blue(username, corp_ticker)) + username_clean = MumbleManager.__santatize_username( + MumbleManager.__generate_username_blue(username, corp_ticker)) password = MumbleManager.__generate_random_pass() pwhash = MumbleManager._gen_pwhash(password) - logger.debug("Proceeding with mumble user creation: clean username %s, pwhash starts with %s" % (username_clean, pwhash[0:5])) + logger.debug("Proceeding with mumble user creation: clean username %s, pwhash starts with %s" % ( + username_clean, pwhash[0:5])) if MumbleUser.objects.filter(username=username_clean).exists() is False: logger.info("Creating mumble user %s" % username_clean) - model = MumbleUser.objects.create(username=username_clean, pwhash=pwhash) + MumbleUser.objects.create(username=username_clean, pwhash=pwhash) return username_clean, password else: logger.warn("Mumble user %s already exists. Updating password") @@ -102,7 +104,7 @@ class MumbleManager: def update_groups(username, groups): logger.debug("Updating mumble user %s groups %s" % (username, groups)) safe_groups = list(set([g.replace(' ', '-') for g in groups])) - groups ='' + groups = '' for g in safe_groups: groups = groups + g + ',' groups = groups.strip(',') diff --git a/services/managers/openfire_manager.py b/services/managers/openfire_manager.py index 5d8c88db..4cdb054a 100755 --- a/services/managers/openfire_manager.py +++ b/services/managers/openfire_manager.py @@ -1,9 +1,14 @@ +from __future__ import unicode_literals +from django.utils import six +import re import os -from urlparse import urlparse +try: + from urlparse import urlparse +except ImportError: + # python 3 + from urllib.parse import urlparse -import xmpp -from django.contrib.auth.models import User -from django.contrib.auth.models import Group +import sleekxmpp from django.conf import settings import threading from ofrestapi.users import Users as ofUsers @@ -13,6 +18,7 @@ import logging logger = logging.getLogger(__name__) + class OpenfireManager: def __init__(self): pass @@ -38,6 +44,11 @@ class OpenfireManager: def __generate_random_pass(): return os.urandom(8).encode('hex') + @staticmethod + def _sanitize_groupname(name): + name = name.strip(' _') + return re.sub('[^\w.-]', '', name) + @staticmethod def add_user(username): logger.debug("Adding username %s to openfire." % username) @@ -95,30 +106,33 @@ class OpenfireManager: return "" @staticmethod - def update_user_groups(username, password, groups): + def update_user_groups(username, groups): logger.debug("Updating openfire user %s groups %s" % (username, groups)) api = ofUsers(settings.OPENFIRE_ADDRESS, settings.OPENFIRE_SECRET_KEY) response = api.get_user_groups(username) remote_groups = [] if response: remote_groups = response['groupname'] - if isinstance(remote_groups, basestring): + if isinstance(remote_groups, six.string_types): remote_groups = [remote_groups] logger.debug("Openfire user %s has groups %s" % (username, remote_groups)) add_groups = [] del_groups = [] for g in groups: - if not g in remote_groups: + g = OpenfireManager._sanitize_groupname(g) + if g not in remote_groups: add_groups.append(g) for g in remote_groups: - if not g in groups: + g = OpenfireManager._sanitize_groupname(g) + if g not in groups: del_groups.append(g) - logger.info("Updating openfire groups for user %s - adding %s, removing %s" % (username, add_groups, del_groups)) + logger.info( + "Updating openfire groups for user %s - adding %s, removing %s" % (username, add_groups, del_groups)) if add_groups: api.add_user_groups(username, add_groups) if del_groups: api.delete_user_groups(username, del_groups) - + @staticmethod def delete_user_groups(username, groups): logger.debug("Deleting openfire groups %s from user %s" % (groups, username)) @@ -129,30 +143,58 @@ class OpenfireManager: @staticmethod def send_broadcast_message(group_name, broadcast_message): logger.debug("Sending jabber ping to group %s with message %s" % (group_name, broadcast_message)) - # create to address - client = xmpp.Client(settings.JABBER_URL) - client.connect(server=(settings.JABBER_SERVER, settings.JABBER_PORT)) - client.auth(settings.BROADCAST_USER, settings.BROADCAST_USER_PASSWORD, 'broadcast') - to_address = group_name + '@' + settings.BROADCAST_SERVICE_NAME + '.' + settings.JABBER_URL - logger.debug("Determined ping to address: %s" % to_address) - message = xmpp.Message(to_address, broadcast_message) - message.setAttr('type', 'chat') - client.send(message) - client.Process(1) + xmpp = PingBot(settings.BROADCAST_USER, settings.BROADCAST_USER_PASSWORD, to_address, broadcast_message) + xmpp.register_plugin('xep_0030') # Service Discovery + xmpp.register_plugin('xep_0199') # XMPP Ping + if xmpp.connect(): + xmpp.process(block=True) + logger.info("Sent jabber ping to group %s" % group_name) + else: + raise ValueError("Unable to connect to jabber server.") - client.disconnect() - logger.info("Sent jabber ping to group %s" % group_name) -class XmppThread (threading.Thread): - def __init__(self, threadID, name, counter, group, message,): +class PingBot(sleekxmpp.ClientXMPP): + """ + A copy-paste of the example client bot from + http://sleekxmpp.com/getting_started/sendlogout.html + """ + def __init__(self, jid, password, recipient, message): + sleekxmpp.ClientXMPP.__init__(self, jid, password) + + # The message we wish to send, and the JID that + # will receive it. + self.recipient = recipient + self.msg = message + + # The session_start event will be triggered when + # the bot establishes its connection with the server + # and the XML streams are ready for use. We want to + # listen for this event so that we we can initialize + # our roster. + self.add_event_handler("session_start", self.start) + + def start(self, event): + self.send_presence() + self.get_roster() + + self.send_message(mto=self.recipient, + mbody=self.msg, + mtype='chat') + + # Using wait=True ensures that the send queue will be + # emptied before ending the session. + self.disconnect(wait=True) + + +class XmppThread(threading.Thread): + def __init__(self, thread_id, name, counter, group, message, ): threading.Thread.__init__(self) - self.threadID = threadID + self.threadID = thread_id self.name = name self.counter = counter self.group = group self.message = message + def run(self): - print "Starting " + self.name OpenfireManager.send_broadcast_message(self.group, self.message) - print "Exiting " + self.name diff --git a/services/managers/pathfinder_manager.py b/services/managers/pathfinder_manager.py deleted file mode 100644 index a06d9353..00000000 --- a/services/managers/pathfinder_manager.py +++ /dev/null @@ -1,196 +0,0 @@ -import logging -from django.conf import settings -import requests -import os -from django.db import connections -from passlib.hash import bcrypt -from eveonline.managers import EveManager -from authentication.managers import AuthServicesInfo -from eveonline.models import EveCharacter -from eveonline.models import EveApiKeyPair - -logger = logging.getLogger(__name__) - -class pathfinderManager: - - SQL_ADD_USER = r"INSERT INTO user (name, email, password, active) VALUES (%s, %s, %s, %s)" - SQL_ADD_API = r"INSERT INTO user_api (userid, keyid, vCode, active) VALUES (%s, %s, %s, %s)" - SQL_ADD_CHARACTER = r"INSERT INTO user_character (userid, apiId, characterId, isMain) VALUES (%s, %s, %s, %s)" - SQL_GET_APIID = r"SELECT id, keyId FROM user_api WHERE userId = %s" - SQL_GET_USERID = r"SELECT id FROM user WHERE name = %s" - SQL_DISABLE_USER = r"UPDATE user SET active = '0' WHERE name = %s" - SQL_UPDATE_USER = r"UPDATE user SET active = '1', password = %s WHERE name = %s" - SQL_CHECK_USER = r"SELECT name FROM user WHERE name = %s" - SQL_CHECK_EMAIL = r"SELECT email from user WHERE email = %s" - SQL_SET_MAIN = r"UPDATE user_character SET isMain = 1 WHERE characterId = %s" - - - @staticmethod - def __santatize_username(username): - sanatized = username.replace(" ", "_") - return sanatized.lower() - - @staticmethod - def __generate_random_pass(): - return os.urandom(8).encode('hex') - - @staticmethod - def check_username(username): - logger.debug("Checking for pathfinder username %s" % username) - cursor = connections['pathfinder'].cursor() - cursor.execute(pathfinderManager.SQL_CHECK_USER, [pathfinderManager.__santatize_username(username)]) - row = cursor.fetchone() - if row: - logger.debug("Found user %s on pathfinder" % username) - return True - logger.debug("User %s not found on pathfinder" % username) - return False - - @staticmethod - def update_user_info(username): - logger.debug("Updating pathfinder user %s" % username) - try: - username_clean = pathfinderManager.__santatize_username(username) - plain_password = pathfinderManager.__generate_random_pass() - passwd = bcrypt.encrypt(plain_password, rounds=10) - cursor = connections['pathfinder'].cursor() - cursor.execute(pathfinderManager.SQL_UPDATE_USER, [passwd, username_clean]) - return username_clean, plain_password - except: - logger.debug("Pathfinder update user failed for %s" % username) - return "", "" - - @staticmethod - def update_custom_password(username, plain_password): - logger.debug("Updating pathfinder user id %s password" % username) - if pathfinderManager.check_username(username): - username_clean = pathfinderManager.__santatize_username(username) - passwd = bcrypt.encrypt(plain_password, rounds=10) - cursor = connections['pathfinder'].cursor() - cursor.execute(pathfinderManager.SQL_UPDATE_USER, [passwd, username_clean]) - return plain_password - else: - logger.error("Unable to update ips4 user %s password" % username) - return "" - - @staticmethod - def disable_user(username): - logger.debug("Disabling user %s" % username) - if pathfinderManager.check_username(username) == True: - try: - cursor = connections['pathfinder'].cursor() - cursor.execute(pathfinderManager.SQL_DISABLE_USER, [pathfinderManager.__santatize_username(username)]) - return True - except: - logger.debug("User %s not found cannot disable" % username) - - - - @staticmethod - def add_user(username, email, charactername): - logger.debug("Adding new pathfinder user %s" % username) - plain_password = pathfinderManager.__generate_random_pass() - passwd = bcrypt.encrypt(plain_password, rounds=10) - username_clean = pathfinderManager.__santatize_username(username) - auth_id = pathfinderManager.get_authid_by_username(charactername) - - if pathfinderManager.check_username(username)== False: - if pathfinderManager.check_email(username, email) == False: - try: - logger.debug("Adding user %s to pathfinder" % username) - cursor = connections['pathfinder'].cursor() - cursor.execute(pathfinderManager.SQL_ADD_USER, [username_clean,email, passwd, '1']) - path_id = pathfinderManager.get_pathfinder_user_id(username_clean) - api_keys = pathfinderManager.get_api_key_pairs(auth_id) - main_character = AuthServicesInfo.objects.get(user=auth_id).main_char_id - - for keyId, key in api_keys.items(): - cursor.execute(pathfinderManager.SQL_ADD_API, [path_id, keyId, key, '1']) - - char_apis = pathfinderManager.get_char_id(auth_id) - - for c,a in char_apis.items(): - cursor.execute(pathfinderManager.SQL_ADD_CHARACTER, [path_id, (pathfinderManager.get_pathfinder_api_id(username, path_id)), c, '0']) - - pathfinderManager.set_main_char(username, main_character) - return username_clean, plain_password - - except: - logger.exception("Unsuccessful attempt at adding user %s to pathfinder on add_user" % username) - return "","" - else: - logger.debug("pathfinder username %s already exists Updating instead" % username) - username_clean, password = pathfinderManager.update_user_info(username) - return username_clean, password - else: - logger.debug("pathfinder username %s already exists Updating instead" % username) - username_clean, password = pathfinderManager.update_user_info(username) - return username_clean, password - - @staticmethod - def set_main_char (username, main_character): - try: - cursor = connections['pathfinder'].cursor() - cursor.execute(pathfinderManager.SQL_SET_MAIN, [main_character]) - except: - logger.debug("Failed setting main character for user %s"% username) - return "" - - @staticmethod - def get_api_key_pairs(user_id): - char = EveCharacter.objects.all().filter(user_id=user_id) - api_list = dict() - for c in char: - api_pair = EveApiKeyPair.objects.get(api_id=c.api_id) - api_list[api_pair.api_id] = api_pair.api_key - return api_list - - @staticmethod - def get_char_id(auth_id): - char = EveCharacter.objects.all().filter(user_id=auth_id) - char_list = dict() - for c in char: - char_list[c.character_id] = c.api_id - logger.debug("printing char list %s" % char_list) - return char_list - - @staticmethod - def get_authid_by_username(username): - authid = EveCharacter.objects.get(character_name=username).user_id - return authid - - @staticmethod - def get_pathfinder_user_id(username): - cursor = connections['pathfinder'].cursor() - cursor.execute(pathfinderManager.SQL_GET_USERID, [username]) - row = cursor.fetchone() - if row: - logger.debug("Pathfinder ID for user %s is %s" % (username, row[0])) - return int(row[0]) - else: - logger.debug("failed to get pathfinder ID for user %s" % username) - return "" - - @staticmethod - def get_pathfinder_api_id(username, path_id): - cursor = connections['pathfinder'].cursor() - cursor.execute(pathfinderManager.SQL_GET_APIID, [path_id]) - row = cursor.fetchone() - if row: - logger.debug("Pathfinder API ID for user %s is %s" % (username, row[0])) - return int(row[0]) - else: - logger.debug("failed to get pathfinder API ID for user %s" % username) - return "" - - @staticmethod - def check_email(username, email): - logger.debug("Checking if email %s exists for username %s" % (email,username)) - cursor = connections['pathfinder'].cursor() - cursor.execute(pathfinderManager.SQL_CHECK_EMAIL, [email]) - row = cursor.fetchone() - if row: - logger.debug("Found user %s email on pathfinder" % username) - return True - logger.debug("User %s email not found on pathfinder" % username) - return False diff --git a/services/managers/phpbb3_manager.py b/services/managers/phpbb3_manager.py index 92384328..55f2e883 100755 --- a/services/managers/phpbb3_manager.py +++ b/services/managers/phpbb3_manager.py @@ -1,5 +1,7 @@ +from __future__ import unicode_literals import os import calendar +import re from datetime import datetime from passlib.apps import phpbb3_context @@ -11,6 +13,7 @@ from django.conf import settings logger = logging.getLogger(__name__) + class Phpbb3Manager: SQL_ADD_USER = r"INSERT INTO phpbb_users (username, username_clean, " \ r"user_password, user_email, group_id, user_regdate, user_permissions, " \ @@ -37,8 +40,9 @@ class Phpbb3Manager: SQL_GET_USER_GROUPS = r"SELECT phpbb_groups.group_name FROM phpbb_groups , phpbb_user_group WHERE " \ r"phpbb_user_group.group_id = phpbb_groups.group_id AND user_id=%s" - SQL_ADD_USER_AVATAR = r"UPDATE phpbb_users SET user_avatar_type=2, user_avatar_width=64, user_avatar_height=64, user_avatar=%s WHERE user_id = %s" - + SQL_ADD_USER_AVATAR = r"UPDATE phpbb_users SET user_avatar_type=2, user_avatar_width=64, user_avatar_height=64, " \ + "user_avatar=%s WHERE user_id = %s" + SQL_CLEAR_USER_PERMISSIONS = r"UPDATE phpbb_users SET user_permissions = '' WHERE user_Id = %s" SQL_DEL_SESSION = r"DELETE FROM phpbb_sessions where session_user_id = %s" @@ -70,6 +74,11 @@ class Phpbb3Manager: sanatized = sanatized.replace("'", "_") return sanatized.lower() + @staticmethod + def _sanitize_groupname(name): + name = name.strip(' _') + return re.sub('[^\w.-]', '', name) + @staticmethod def __get_group_id(groupname): logger.debug("Getting phpbb3 group id for groupname %s" % groupname) @@ -153,7 +162,8 @@ class Phpbb3Manager: @staticmethod def add_user(username, email, groups, characterid): - logger.debug("Adding phpbb user with username %s, email %s, groups %s, characterid %s" % (username, email, groups, characterid)) + logger.debug("Adding phpbb user with username %s, email %s, groups %s, characterid %s" % ( + username, email, groups, characterid)) cursor = connections['phpbb3'].cursor() username_clean = Phpbb3Manager.__santatize_username(username) @@ -195,7 +205,7 @@ class Phpbb3Manager: Phpbb3Manager.update_groups(username, []) logger.info("Disabled phpbb user %s" % username) return True - except TypeError as e: + except TypeError: logger.exception("TypeError occured while disabling user %s - failed to disable." % username) return False @@ -218,7 +228,7 @@ class Phpbb3Manager: if userid is not None: forum_groups = Phpbb3Manager.__get_all_groups() user_groups = set(Phpbb3Manager.__get_user_groups(userid)) - act_groups = set([g.replace(' ', '-') for g in groups]) + act_groups = set([Phpbb3Manager._sanitize_groupname(g) for g in groups]) addgroups = act_groups - user_groups remgroups = user_groups - act_groups logger.info("Updating phpbb user %s groups - adding %s, removing %s" % (username, addgroups, remgroups)) @@ -244,7 +254,9 @@ class Phpbb3Manager: cursor.execute(Phpbb3Manager.SQL_REMOVE_USER_GROUP, [userid, groupid]) logger.info("Removed phpbb user %s from group %s" % (username, group)) except: - logger.exception("Exception prevented removal of phpbb user %s with id %s from group %s with id %s" % (username, userid, group, groupid)) + logger.exception( + "Exception prevented removal of phpbb user %s with id %s from group %s with id %s" % ( + username, userid, group, groupid)) pass @staticmethod @@ -267,7 +279,8 @@ class Phpbb3Manager: password = Phpbb3Manager.__generate_random_pass() if Phpbb3Manager.check_user(username): pwhash = Phpbb3Manager.__gen_hash(password) - logger.debug("Proceeding to update phpbb user %s password with pwhash starting with %s" % (username, pwhash[0:5])) + logger.debug( + "Proceeding to update phpbb user %s password with pwhash starting with %s" % (username, pwhash[0:5])) cursor.execute(Phpbb3Manager.SQL_UPDATE_USER_PASSWORD, [pwhash, username]) Phpbb3Manager.__add_avatar(username, characterid) logger.info("Updated phpbb user %s password." % username) @@ -277,7 +290,8 @@ class Phpbb3Manager: @staticmethod def __update_user_info(username, email, password): - logger.debug("Updating phpbb user %s info: username %s password of length %s" % (username, email, len(password))) + logger.debug( + "Updating phpbb user %s info: username %s password of length %s" % (username, email, len(password))) cursor = connections['phpbb3'].cursor() try: cursor.execute(Phpbb3Manager.SQL_DIS_USER, [email, password, username]) diff --git a/services/managers/smf_manager.py b/services/managers/smf_manager.py index 701f63c5..a8352c7b 100644 --- a/services/managers/smf_manager.py +++ b/services/managers/smf_manager.py @@ -1,15 +1,21 @@ +from __future__ import unicode_literals import os import calendar from datetime import datetime import hashlib import logging +import re from django.db import connections from django.conf import settings logger = logging.getLogger(__name__) + class smfManager: + def __init__(self): + pass + SQL_ADD_USER = r"INSERT INTO smf_members (member_name, passwd, email_address, date_registered, real_name," \ r" buddy_list, message_labels, openid_uri, signature, ignore_boards) " \ r"VALUES (%s, %s, %s, %s, %s, 0, 0, 0, 0, 0)" @@ -36,7 +42,10 @@ class smfManager: SQL_ADD_USER_AVATAR = r"UPDATE smf_members SET avatar = %s WHERE id_member = %s" - + @staticmethod + def _sanitize_groupname(name): + name = name.strip(' _') + return re.sub('[^\w.-]', '', name) @staticmethod def generate_random_pass(): @@ -44,7 +53,7 @@ class smfManager: @staticmethod def gen_hash(username_clean, passwd): - return hashlib.sha1((username_clean) + passwd).hexdigest() + return hashlib.sha1(username_clean + passwd).hexdigest() @staticmethod def santatize_username(username): @@ -66,7 +75,6 @@ class smfManager: logger.info("Created smf group %s" % groupname) return smfManager.get_group_id(groupname) - @staticmethod def get_group_id(groupname): logger.debug("Getting smf group id for groupname %s" % groupname) @@ -88,7 +96,6 @@ class smfManager: logger.debug("User %s not found on smf" % username) return False - @staticmethod def add_avatar(member_name, characterid): logger.debug("Adding EVE character id %s portrait as smf avatar for user %s" % (characterid, member_name)) @@ -133,7 +140,8 @@ class smfManager: @staticmethod def add_user(username, email_address, groups, characterid): - logger.debug("Adding smf user with member_name %s, email_address %s, characterid %s" % (username, email_address, characterid)) + logger.debug("Adding smf user with member_name %s, email_address %s, characterid %s" % ( + username, email_address, characterid)) cursor = connections['smf'].cursor() username_clean = smfManager.santatize_username(username) passwd = smfManager.generate_random_pass() @@ -141,12 +149,13 @@ class smfManager: logger.debug("Proceeding to add smf user %s and pwhash starting with %s" % (username, pwhash[0:5])) register_date = smfManager.get_current_utc_date() # check if the username was simply revoked - if smfManager.check_user(username)is True : + if smfManager.check_user(username) is True: logger.warn("Unable to add smf user with username %s - already exists. Updating user instead." % username) smfManager.__update_user_info(username_clean, email_address, pwhash) else: try: - cursor.execute(smfManager.SQL_ADD_USER, [username_clean, passwd, email_address, register_date, username_clean]) + cursor.execute(smfManager.SQL_ADD_USER, + [username_clean, passwd, email_address, register_date, username_clean]) smfManager.add_avatar(username_clean, characterid) logger.info("Added smf member_name %s" % username_clean) smfManager.update_groups(username_clean, groups) @@ -157,7 +166,8 @@ class smfManager: @staticmethod def __update_user_info(username, email_address, passwd): - logger.debug("Updating smf user %s info: username %s password of length %s" % (username, email_address, len(passwd))) + logger.debug( + "Updating smf user %s info: username %s password of length %s" % (username, email_address, len(passwd))) cursor = connections['smf'].cursor() try: cursor.execute(smfManager.SQL_DIS_USER, [email_address, passwd, username]) @@ -185,19 +195,18 @@ class smfManager: if userid is not None: forum_groups = smfManager.get_all_groups() user_groups = set(smfManager.get_user_groups(userid)) - act_groups = set([g.replace(' ', '-') for g in groups]) + act_groups = set([smfManager._sanitize_groupname(g) for g in groups]) addgroups = act_groups - user_groups remgroups = user_groups - act_groups logger.info("Updating smf user %s groups - adding %s, removing %s" % (username, addgroups, remgroups)) act_group_id = set() for g in addgroups: - if not g in forum_groups: + if g not in forum_groups: forum_groups[g] = smfManager.create_group(g) act_group_id.add(str(smfManager.get_group_id(g))) string_groups = ','.join(act_group_id) smfManager.add_user_to_group(userid, string_groups) - @staticmethod def add_user_to_group(userid, groupid): logger.debug("Adding smf user id %s to group id %s" % (userid, groupid)) @@ -230,11 +239,11 @@ class smfManager: try: pwhash = smfManager.gen_hash(username, password) cursor.execute(smfManager.SQL_DIS_USER, [revoke_email, pwhash, username]) - userid = smfManager.get_user_id(username) + smfManager.get_user_id(username) smfManager.update_groups(username, []) logger.info("Disabled smf user %s" % username) return True - except TypeError as e: + except TypeError: logger.exception("TypeError occured while disabling user %s - failed to disable." % username) return False @@ -247,14 +256,11 @@ class smfManager: if smfManager.check_user(username): username_clean = smfManager.santatize_username(username) pwhash = smfManager.gen_hash(username_clean, password) - logger.debug("Proceeding to update smf user %s password with pwhash starting with %s" % (username, pwhash[0:5])) + logger.debug( + "Proceeding to update smf user %s password with pwhash starting with %s" % (username, pwhash[0:5])) cursor.execute(smfManager.SQL_UPDATE_USER_PASSWORD, [pwhash, username]) smfManager.add_avatar(username, characterid) logger.info("Updated smf user %s password." % username) return password logger.error("Unable to update smf user %s password - user not found on smf." % username) return "" - - - - diff --git a/services/managers/srp_manager.py b/services/managers/srp_manager.py index 6bd2f8b9..007a044e 100644 --- a/services/managers/srp_manager.py +++ b/services/managers/srp_manager.py @@ -1,46 +1,49 @@ +from __future__ import unicode_literals from django.conf import settings - -import json -import urllib2 +import requests import logging - logger = logging.getLogger(__name__) -class srpManager(): + +class srpManager: + def __init__(self): + pass + @staticmethod - def get_kill_id (killboard_link): - str = (killboard_link) - set = '0123456789' - kill_id = ''.join([c for c in str if c in set]) + def get_kill_id(killboard_link): + num_set = '0123456789' + kill_id = ''.join([c for c in killboard_link if c in num_set]) return kill_id @staticmethod - def get_kill_data (kill_id): + def get_kill_data(kill_id): url = ("https://www.zkillboard.com/api/killID/%s" % kill_id) - request = urllib2.Request(url) - request.add_header('User-Agent',"%s Alliance Auth" % settings.DOMAIN) - request.add_header('Content-Type','application/json') - response = urllib2.urlopen(request) - result = json.load(response)[0] + headers = { + 'User-Agent': "%s Alliance Auth" % settings.DOMAIN, + 'Content-Type': 'application/json', + } + r = requests.get(url, headers=headers) + result = r.json()[0] if result: ship_type = result['victim']['shipTypeID'] logger.debug("Ship type for kill ID %s is determined to be %s" % (kill_id, ship_type)) ship_value = result['zkb']['totalValue'] - logger.debug("total loss value for kill id %s is %s" %(kill_id, ship_value)) - return (ship_type, ship_value) + logger.debug("total loss value for kill id %s is %s" % (kill_id, ship_value)) + return ship_type, ship_value else: raise ValueError("Invalid Kill ID") @staticmethod - def get_ship_name (ship_type): + def get_ship_name(ship_type): url = ("https://jetbalsa.com/api/json.php/invTypes/%s" % ship_type) - request = urllib2.Request(url) - request.add_header('User-Agent',"%s Alliance Auth" % settings.DOMAIN) - request.add_header('Content-Type','application/json') - response = urllib2.urlopen(request) - result = json.load(response) + headers = { + 'User-Agent': "%s Alliance Auth" % settings.DOMAIN, + 'Content-Type': 'application/json', + } + r = requests.get(url, headers=headers) + result = r.json() if result: ship_name = result['typeName'] logger.debug("ship type %s determined to be %s" % (ship_type, ship_name)) @@ -48,13 +51,3 @@ class srpManager(): else: logger.debug("ship type %s is invalid" % ship_type) raise ValueError("Cannot get ship name") - - - - - - - - - - diff --git a/services/managers/teamspeak3_manager.py b/services/managers/teamspeak3_manager.py index 82f54a8c..e2c060bb 100755 --- a/services/managers/teamspeak3_manager.py +++ b/services/managers/teamspeak3_manager.py @@ -1,11 +1,13 @@ +from __future__ import unicode_literals from django.conf import settings -from services.managers.util.ts3 import TS3Server +from services.managers.util.ts3 import TS3Server, TeamspeakError from services.models import TSgroup import logging logger = logging.getLogger(__name__) + class Teamspeak3Manager: def __init__(self): pass @@ -117,10 +119,9 @@ class Teamspeak3Manager: def _add_user_to_group(uid, groupid): logger.debug("Adding group id %s to TS3 user id %s" % (groupid, uid)) server = Teamspeak3Manager.__get_created_server() - server_groups = Teamspeak3Manager._group_list() user_groups = Teamspeak3Manager._user_group_list(uid) - - if not groupid in user_groups.values(): + + if groupid not in user_groups.values(): logger.debug("User does not have group already. Issuing command to add.") server.send_command('servergroupaddclient', {'sgid': str(groupid), 'cldbid': uid}) @@ -130,7 +131,6 @@ class Teamspeak3Manager: def _remove_user_from_group(uid, groupid): logger.debug("Removing group id %s from TS3 user id %s" % (groupid, uid)) server = Teamspeak3Manager.__get_created_server() - server_groups = Teamspeak3Manager._group_list() user_groups = Teamspeak3Manager._user_group_list(uid) if str(groupid) in user_groups.values(): @@ -149,39 +149,45 @@ class Teamspeak3Manager: for key in remote_groups: logger.debug("Typecasting remote_group value at position %s to int: %s" % (key, remote_groups[key])) remote_groups[key] = int(remote_groups[key]) - + for group in local_groups: logger.debug("Checking local group %s" % group) if group.ts_group_id not in remote_groups.values(): - logger.debug("Local group id %s not found on server. Deleting model %s" % (group.ts_group_id, group)) + logger.debug( + "Local group id %s not found on server. Deleting model %s" % (group.ts_group_id, group)) TSgroup.objects.filter(ts_group_id=group.ts_group_id).delete() for key in remote_groups: - g = TSgroup(ts_group_id=remote_groups[key],ts_group_name=key) + g = TSgroup(ts_group_id=remote_groups[key], ts_group_name=key) q = TSgroup.objects.filter(ts_group_id=g.ts_group_id) if not q: - logger.debug("Local group does not exist for TS group %s. Creating TSgroup model %s" % (remote_groups[key], g)) + logger.debug("Local group does not exist for TS group %s. Creating TSgroup model %s" % ( + remote_groups[key], g)) g.save() + except TeamspeakError as e: + logger.error("Error occured while syncing TS group db: %s" % str(e)) except: logger.exception("An unhandled exception has occured while syncing TS groups.") - pass @staticmethod def add_user(username, corp_ticker): username_clean = Teamspeak3Manager.__santatize_username(Teamspeak3Manager.__generate_username(username, - corp_ticker)) + corp_ticker)) server = Teamspeak3Manager.__get_created_server() - token = "" logger.debug("Adding user to TS3 server with cleaned username %s" % username_clean) server_groups = Teamspeak3Manager._group_list() - if not settings.DEFAULT_AUTH_GROUP in server_groups: + if settings.DEFAULT_AUTH_GROUP not in server_groups: Teamspeak3Manager._create_group(settings.DEFAULT_AUTH_GROUP) alliance_group_id = Teamspeak3Manager._group_id_by_name(settings.DEFAULT_AUTH_GROUP) - ret = server.send_command('tokenadd', {'tokentype': 0, 'tokenid1': alliance_group_id, 'tokenid2': 0, - 'tokendescription': username_clean, - 'tokencustomset': "ident=sso_uid value=%s" % username_clean}) + try: + ret = server.send_command('tokenadd', {'tokentype': 0, 'tokenid1': alliance_group_id, 'tokenid2': 0, + 'tokendescription': username_clean, + 'tokencustomset': "ident=sso_uid value=%s" % username_clean}) + except TeamspeakError as e: + logger.error("Failed to add teamspeak user %s: %s" % (username, str(e))) + return "","" try: token = ret['keys']['token'] @@ -189,24 +195,27 @@ class Teamspeak3Manager: return username_clean, token except: logger.exception("Failed to add teamspeak user %s - received response: %s" % (username_clean, ret)) - return "","" + return "", "" @staticmethod def add_blue_user(username, corp_ticker): username_clean = Teamspeak3Manager.__santatize_username(Teamspeak3Manager.__generate_username_blue(username, - corp_ticker)) + corp_ticker)) server = Teamspeak3Manager.__get_created_server() - token = "" logger.debug("Adding user to TS3 server with cleaned username %s" % username_clean) server_groups = Teamspeak3Manager._group_list() - if not settings.DEFAULT_BLUE_GROUP in server_groups: + if settings.DEFAULT_BLUE_GROUP not in server_groups: Teamspeak3Manager._create_group(settings.DEFAULT_BLUE_GROUP) blue_group_id = Teamspeak3Manager._group_id_by_name(settings.DEFAULT_BLUE_GROUP) - ret = server.send_command('tokenadd', {'tokentype': 0, 'tokenid1': blue_group_id, 'tokenid2': 0, - 'tokendescription': username_clean, - 'tokencustomset': "ident=sso_uid value=%s" % username_clean}) + try: + ret = server.send_command('tokenadd', {'tokentype': 0, 'tokenid1': blue_group_id, 'tokenid2': 0, + 'tokendescription': username_clean, + 'tokencustomset': "ident=sso_uid value=%s" % username_clean}) + except TeamspeakError as e: + logger.error("Failed to add blue teamspeak user %s: %s" % (username, str(e))) + return "","" try: token = ret['keys']['token'] @@ -214,10 +223,7 @@ class Teamspeak3Manager: return username_clean, token except: logger.exception("Failed to add blue teamspeak user %s - received response: %s" % (username_clean, ret)) - return "","" - - - + return "", "" @staticmethod def delete_user(uid): @@ -235,7 +241,12 @@ class Teamspeak3Manager: logger.exception("Failed to delete user id %s from TS3 - received response %s" % (uid, client)) return False - ret = server.send_command('clientdbdelete', {'cldbid': user}) + try: + ret = server.send_command('clientdbdelete', {'cldbid': user}) + except TeamspeakError as e: + logger.error("Failed to delete teamspeak user %s: %s" % (uid, str(e))) + return False + if ret == '0': logger.info("Deleted user with id %s from TS3 server." % uid) return True @@ -291,4 +302,3 @@ class Teamspeak3Manager: for g in remgroups: logger.info("Removing Teamspeak user %s from group %s" % (userid, g)) Teamspeak3Manager._remove_user_from_group(userid, g) - diff --git a/services/managers/util/__init__.py b/services/managers/util/__init__.py index 8fdaf87a..81a621a7 100755 --- a/services/managers/util/__init__.py +++ b/services/managers/util/__init__.py @@ -1 +1,2 @@ +from __future__ import unicode_literals __author__ = 'r4stl1n' diff --git a/services/managers/util/ts3.py b/services/managers/util/ts3.py index 1122737b..f61c304b 100755 --- a/services/managers/util/ts3.py +++ b/services/managers/util/ts3.py @@ -1,8 +1,9 @@ +from __future__ import unicode_literals import socket import logging -class ConnectionError(): +class ConnectionError: def __init__(self, ip, port): self.ip = ip self.port = port @@ -22,8 +23,7 @@ ts3_escape = {'/': r"\/", "\t": r'\t', "\v": r'\v'} - -class TS3Proto(): +class TS3Proto: bytesin = 0 bytesout = 0 @@ -66,7 +66,7 @@ class TS3Proto(): while True: resp = self._sockfile.readline() resp = self.parse_command(resp) - if not 'command' in resp: + if 'command' not in resp: data.append(resp) else: break @@ -78,7 +78,7 @@ class TS3Proto(): else: return data[0] else: - return resp['keys']['id'] + raise TeamspeakError(resp['keys']['id']) def construct_command(self, command, keys=None, opts=None): """ @@ -139,7 +139,7 @@ class TS3Proto(): v = [v[0], '='.join(v[1:])] key, value = v keys[key] = self._unescape_str(value) - elif (not v == ['']): + elif not v == ['']: if v[0][0] and v[0][0] == '-': # Option opts.append(v[0][1:]) @@ -159,9 +159,10 @@ class TS3Proto(): @type value: string/int """ - if isinstance(value, int): return "%d" % value + if isinstance(value, int): + return "%d" % value value = value.replace("\\", r'\\') - for i, j in ts3_escape.iteritems(): + for i, j in ts3_escape: value = value.replace(i, j) return value @@ -173,13 +174,13 @@ class TS3Proto(): @type value: string/int """ - if isinstance(value, int): return "%d" % value + if isinstance(value, int): + return "%d" % value value = value.replace(r"\\", "\\") - for i, j in ts3_escape.iteritems(): + for i, j in ts3_escape: value = value.replace(j, i) return value - def send(self, payload): if self._connected: self._log.debug('Sent: %s' % payload) @@ -230,7 +231,7 @@ class TS3Server(TS3Proto): """ Send a global message to the current Virtual Server @param msg: Message - @type ip: str + @type msg: str """ if self._connected: return self.send_command('gm', keys={'msg': msg}) @@ -243,3 +244,213 @@ class TS3Server(TS3Proto): """ if self._connected and id > 0: self.send_command('use', keys={'sid': id}) + + +class TeamspeakError: + def __init__(self, code, msg=None): + self.code = str(code) + if not msg: + msg = ts3_errors[self.code] + self.msg = msg + + def __str__(self): + return self.code + ' ' + self.msg + +ts3_errors = { + '0': 'unknown error code', + '1': 'undefined error', + '2': 'not implemented', + '3': '', + '4': '', + '5': 'library time limit reached', + '256': 'command not found', + '257': 'unable to bind network port', + '258': 'no network port available', + '512': 'invalid clientID', + '513': 'nickname is already in use', + '514': 'invalid error code', + '515': 'max clients protocol limit reached', + '516': 'invalid client type', + '517': 'already subscribed', + '518': 'not logged in', + '519': 'could not validate client identity', + '520': 'invalid loginname or password', + '521': 'too many clones already connected', + '522': 'client version outdated, please update', + '523': 'client is online', + '524': 'client is flooding', + '525': 'client is modified', + '526': 'can not verify client at this moment', + '527': 'client is not permitted to log in', + '528': 'client is not subscribed to the channel', + '768': 'invalid channelID', + '769': 'max channels protocol limit reached', + '770': 'already member of channel', + '771': 'channel name is already in use', + '772': 'channel not empty', + '773': 'can not delete default channel', + '774': 'default channel requires permanent', + '775': 'invalid channel flags', + '776': 'permanent channel can not be child of non permanent channel', + '777': 'channel maxclient reached', + '778': 'channel maxfamily reached', + '779': 'invalid channel order', + '780': 'channel does not support filetransfers', + '781': 'invalid channel password', + '782': 'channel is private channel', + '783': 'invalid security hash supplied by client', + '1024': 'invalid serverID', + '1025': 'server is running', + '1026': 'server is shutting down', + '1027': 'server maxclient reached', + '1028': 'invalid server password', + '1029': 'deployment active', + '1030': 'unable to stop own server in your connection class', + '1031': 'server is virtual', + '1032': 'server wrong machineID', + '1033': 'server is not running', + '1034': 'server is booting up', + '1035': 'server got an invalid status for this operation', + '1036': 'server modal quit', + '1037': 'server version is too old for command', + '1280': 'database error', + '1281': 'database empty result set', + '1282': 'database duplicate entry', + '1283': 'database no modifications', + '1284': 'database invalid constraint', + '1285': 'database reinvoke command', + '1536': 'invalid quote', + '1537': 'invalid parameter count', + '1538': 'invalid parameter', + '1539': 'parameter not found', + '1540': 'convert error', + '1541': 'invalid parameter size', + '1542': 'missing required parameter', + '1543': 'invalid checksum', + '1792': 'virtual server got a critical error', + '1793': 'Connection lost', + '1794': 'not connected', + '1795': 'no cached connection info', + '1796': 'currently not possible', + '1797': 'failed connection initialization', + '1798': 'could not resolve hostname', + '1799': 'invalid server connection handler ID', + '1800': 'could not initialize Input Manager', + '1801': 'client library not initialized', + '1802': 'server library not initialized', + '1803': 'too many whisper targets', + '1804': 'no whisper targets found', + '2048': 'invalid file name', + '2049': 'invalid file permissions', + '2050': 'file already exists', + '2051': 'file not found', + '2052': 'file input/output error', + '2053': 'invalid file transfer ID', + '2054': 'invalid file path', + '2055': 'no files available', + '2056': 'overwrite excludes resume', + '2057': 'invalid file size', + '2058': 'file already in use', + '2059': 'could not open file transfer connection', + '2060': 'no space left on device (disk full?)', + '2061': "file exceeds file system's maximum file size", + '2062': 'file transfer connection timeout', + '2063': 'lost file transfer connection', + '2064': 'file exceeds supplied file size', + '2065': 'file transfer complete', + '2066': 'file transfer canceled', + '2067': 'file transfer interrupted', + '2068': 'file transfer server quota exceeded', + '2069': 'file transfer client quota exceeded', + '2070': 'file transfer reset', + '2071': 'file transfer limit reached', + '2304': 'preprocessor disabled', + '2305': 'internal preprocessor', + '2306': 'internal encoder', + '2307': 'internal playback', + '2308': 'no capture device available', + '2309': 'no playback device available', + '2310': 'could not open capture device', + '2311': 'could not open playback device', + '2312': 'ServerConnectionHandler has a device registered', + '2313': 'invalid capture device', + '2314': 'invalid clayback device', + '2315': 'invalid wave file', + '2316': 'wave file type not supported', + '2317': 'could not open wave file', + '2318': 'internal capture', + '2319': 'device still in use', + '2320': 'device already registerred', + '2321': 'device not registered/known', + '2322': 'unsupported frequency', + '2323': 'invalid channel count', + '2324': 'read error in wave', + '2325': 'sound need more data', + '2326': 'sound device was busy', + '2327': 'there is no sound data for this period', + '2328': 'Channelmask set bits count (speakers) is not the same as channel (count)', + '2560': 'invalid group ID', + '2561': 'duplicate entry', + '2562': 'invalid permission ID', + '2563': 'empty result set', + '2564': 'access to default group is forbidden', + '2565': 'invalid size', + '2566': 'invalid value', + '2567': 'group is not empty', + '2568': 'insufficient client permissions', + '2569': 'insufficient group modify power', + '2570': 'insufficient permission modify power', + '2571': 'template group is currently used', + '2572': 'permission error', + '2816': 'virtualserver limit reached', + '2817': 'max slot limit reached', + '2818': 'license file not found', + '2819': 'license date not ok', + '2820': 'unable to connect to accounting server', + '2821': 'unknown accounting error', + '2822': 'accounting server error', + '2823': 'instance limit reached', + '2824': 'instance check error', + '2825': 'license file invalid', + '2826': 'virtualserver is running elsewhere', + '2827': 'virtualserver running in same instance already', + '2828': 'virtualserver already started', + '2829': 'virtualserver not started', + '2830': '', + '3072': 'invalid message id', + '3328': 'invalid ban id', + '3329': 'connection failed, you are banned', + '3330': 'rename failed, new name is banned', + '3331': 'flood ban', + '3584': 'unable to initialize tts', + '3840': 'invalid privilege key', + '4096': '', + '4097': '', + '4098': '', + '4099': '', + '4100': '', + '4101': '', + '4102': '', + '4103': '', + '4352': 'invalid password', + '4353': 'invalid request', + '4354': 'no (more) slots available', + '4355': 'pool missing', + '4356': 'pool unknown', + '4357': 'unknown ip location (perhaps LAN ip?)', + '4358': 'internal error (tried exceeded)', + '4359': 'too many slots requested', + '4360': 'too many reserved', + '4361': 'could not connect to provisioning server', + '4368': 'authentication server not connected', + '4369': 'authentication data too large', + '4370': 'already initialized', + '4371': 'not initialized', + '4372': 'already connecting', + '4373': 'already connected', + '4374': '', + '4375': 'io_error', + '4376': '', + '4377': '', + '4378': '', +} diff --git a/services/managers/xenforo_manager.py b/services/managers/xenforo_manager.py index 18050201..aaa4ca3f 100644 --- a/services/managers/xenforo_manager.py +++ b/services/managers/xenforo_manager.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals import os import requests import json @@ -8,130 +9,131 @@ import logging logger = logging.getLogger(__name__) + class XenForoManager: - def __init__(self): - if not settings.XENFORO_ENDPOINT: - logger.debug("Could not find XenForo endpoint") - if not settings.XENFORO_APIKEY: - logger.debug("XenForo API Key not found") - pass + def __init__(self): + if not settings.XENFORO_ENDPOINT: + logger.debug("Could not find XenForo endpoint") + if not settings.XENFORO_APIKEY: + logger.debug("XenForo API Key not found") + pass - @staticmethod - def __sanitize_username(username): - sanitized = username.replace(" ", "_") - return sanitized + @staticmethod + def __sanitize_username(username): + sanitized = username.replace(" ", "_") + return sanitized - @staticmethod - def __generate_password(): - return os.urandom(8).encode('hex') + @staticmethod + def __generate_password(): + return os.urandom(8).encode('hex') - @staticmethod - def exec_http_request(http_params): - default_params = { - 'hash': settings.XENFORO_APIKEY - } - http_params.update(default_params) - r = requests.get(settings.XENFORO_ENDPOINT, params=http_params) - return r + @staticmethod + def exec_http_request(http_params): + default_params = { + 'hash': settings.XENFORO_APIKEY + } + http_params.update(default_params) + r = requests.get(settings.XENFORO_ENDPOINT, params=http_params) + return r - @staticmethod - def add_user(username, email): + @staticmethod + def add_user(username, email): - sanitized = XenForoManager.__sanitize_username(username) - password = XenForoManager.__generate_password(); + sanitized = XenForoManager.__sanitize_username(username) + password = XenForoManager.__generate_password() - data = { - 'action': 'register', - 'username': sanitized, - 'password': password, - 'email': email, - 'group': settings.XENFORO_DEFAULT_GROUP, - 'visible': '1', - 'user_state': 'valid' - } + data = { + 'action': 'register', + 'username': sanitized, + 'password': password, + 'email': email, + 'group': settings.XENFORO_DEFAULT_GROUP, + 'visible': '1', + 'user_state': 'valid' + } - r = XenForoManager.exec_http_request(data) - - # check if the user already exist but was disabled - if r.status_code != 200: - if json.loads(r.text)['error'] == 7: - data = XenForoManager.reactivate_user(sanitized) - return data + r = XenForoManager.exec_http_request(data) - response = { - 'response': { - 'message': r.text, - 'status_code': r.status_code - } - } - data.update(response) - return data + # check if the user already exist but was disabled + if r.status_code != 200: + if json.loads(r.text)['error'] == 7: + data = XenForoManager.reactivate_user(sanitized) + return data - @staticmethod - def reset_password(username): + response = { + 'response': { + 'message': r.text, + 'status_code': r.status_code + } + } + data.update(response) + return data - password = XenForoManager.__generate_password(); + @staticmethod + def reset_password(username): - data = { - 'action': 'editUser', - 'user': username, - 'password': password - } + password = XenForoManager.__generate_password() - r = XenForoManager.exec_http_request(data) + data = { + 'action': 'editUser', + 'user': username, + 'password': password + } - response = { - 'response': { - 'message': r.text, - 'status_code': r.status_code - } - } - data.update(response) - return data + r = XenForoManager.exec_http_request(data) - @staticmethod - def disable_user(username): - data = { - 'action': 'editUser', - 'user': username, - 'remove_groups': settings.XENFORO_DEFAULT_GROUP - } - r = XenForoManager.exec_http_request(data) - return r + response = { + 'response': { + 'message': r.text, + 'status_code': r.status_code + } + } + data.update(response) + return data - @staticmethod - def reactivate_user(username): - data = { - 'action': 'editUser', - 'user': username, - 'add_groups': settings.XENFORO_DEFAULT_GROUP, - 'password': XenForoManager.__generate_password() - } - r = XenForoManager.exec_http_request(data) - response = { - 'response': { - 'message': r.text, - 'status_code': r.status_code - }, - 'username': username - } - data.update(response) - return data + @staticmethod + def disable_user(username): + data = { + 'action': 'editUser', + 'user': username, + 'remove_groups': settings.XENFORO_DEFAULT_GROUP + } + r = XenForoManager.exec_http_request(data) + return r - @staticmethod - def update_user_password(username, raw_password): - data = { - 'action': 'editUser', - 'user': username, - 'password': raw_password - } - r = XenForoManager.exec_http_request(data) - response = { - 'response': { - 'message': r.text, - 'status_code': r.status_code - }, - 'username': username - } - data.update(response) - return data \ No newline at end of file + @staticmethod + def reactivate_user(username): + data = { + 'action': 'editUser', + 'user': username, + 'add_groups': settings.XENFORO_DEFAULT_GROUP, + 'password': XenForoManager.__generate_password() + } + r = XenForoManager.exec_http_request(data) + response = { + 'response': { + 'message': r.text, + 'status_code': r.status_code + }, + 'username': username + } + data.update(response) + return data + + @staticmethod + def update_user_password(username, raw_password): + data = { + 'action': 'editUser', + 'user': username, + 'password': raw_password + } + r = XenForoManager.exec_http_request(data) + response = { + 'response': { + 'message': r.text, + 'status_code': r.status_code + }, + 'username': username + } + data.update(response) + return data diff --git a/services/migrations/0001_initial.py b/services/migrations/0001_initial.py new file mode 100644 index 00000000..5787cfb8 --- /dev/null +++ b/services/migrations/0001_initial.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-05 21:40 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0008_alter_user_username_max_length'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='AuthTS', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('auth_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.Group')), + ], + options={ + 'verbose_name': 'Auth / TS Group', + }, + ), + migrations.CreateModel( + name='DiscordAuthToken', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('email', models.CharField(max_length=254, unique=True)), + ('token', models.CharField(max_length=254)), + ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='GroupCache', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(auto_now_add=True)), + ('groups', models.TextField(default={})), + ('service', models.CharField(choices=[(b'discourse', b'discourse'), (b'discord', b'discord')], max_length=254, unique=True)), + ], + ), + migrations.CreateModel( + name='MumbleUser', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('username', models.CharField(max_length=254, unique=True)), + ('pwhash', models.CharField(max_length=40)), + ('groups', models.TextField(blank=True, null=True)), + ], + ), + migrations.CreateModel( + name='TSgroup', + fields=[ + ('ts_group_id', models.IntegerField(primary_key=True, serialize=False)), + ('ts_group_name', models.CharField(max_length=30)), + ], + options={ + 'verbose_name': 'TS Group', + }, + ), + migrations.CreateModel( + name='UserTSgroup', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('ts_group', models.ManyToManyField(to='services.TSgroup')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'User TS Group', + }, + ), + migrations.AddField( + model_name='authts', + name='ts_group', + field=models.ManyToManyField(to='services.TSgroup'), + ), + ] diff --git a/services/migrations/0002_auto_20161016_0135.py b/services/migrations/0002_auto_20161016_0135.py new file mode 100644 index 00000000..68749395 --- /dev/null +++ b/services/migrations/0002_auto_20161016_0135.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-10-16 01:35 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('services', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='discordauthtoken', + name='user', + ), + migrations.DeleteModel( + name='DiscordAuthToken', + ), + ] diff --git a/services/migrations/__init__.py b/services/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/services/models.py b/services/models.py index 3ff5c786..80b62c08 100644 --- a/services/models.py +++ b/services/models.py @@ -1,44 +1,45 @@ +from __future__ import unicode_literals +from django.utils.encoding import python_2_unicode_compatible from django.db import models -from django.contrib.auth.models import Group, User + +@python_2_unicode_compatible class TSgroup(models.Model): ts_group_id = models.IntegerField(primary_key=True) ts_group_name = models.CharField(max_length=30) class Meta: - verbose_name='TS Group' + verbose_name = 'TS Group' def __str__(self): return self.ts_group_name - + + +@python_2_unicode_compatible class AuthTS(models.Model): auth_group = models.ForeignKey('auth.Group') ts_group = models.ManyToManyField(TSgroup) class Meta: - verbose_name='Auth / TS Group' + verbose_name = 'Auth / TS Group' def __str__(self): return self.auth_group.name + +@python_2_unicode_compatible class UserTSgroup(models.Model): user = models.ForeignKey('auth.User') ts_group = models.ManyToManyField(TSgroup) class Meta: - verbose_name='User TS Group' + verbose_name = 'User TS Group' def __str__(self): return self.user.name -class DiscordAuthToken(models.Model): - email = models.CharField(max_length=254, unique=True) - token = models.CharField(max_length=254) - user = models.ForeignKey(User, on_delete=models.CASCADE, null=True) - def __str__(self): - output = "Discord Token for email %s user %s" % (self.email, self.user) - return output.encode('utf-8') +@python_2_unicode_compatible class MumbleUser(models.Model): username = models.CharField(max_length=254, unique=True) pwhash = models.CharField(max_length=40) @@ -47,6 +48,8 @@ class MumbleUser(models.Model): def __str__(self): return self.username + +@python_2_unicode_compatible class GroupCache(models.Model): SERVICE_CHOICES = ( ("discourse", "discourse"), diff --git a/celerytask/signals.py b/services/signals.py similarity index 81% rename from celerytask/signals.py rename to services/signals.py index 0ca303f8..acc1102d 100644 --- a/celerytask/signals.py +++ b/services/signals.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals from django.db.models.signals import m2m_changed from django.db.models.signals import post_save from django.db.models.signals import pre_save @@ -6,25 +7,26 @@ from django.db.models.signals import pre_delete from django.dispatch import receiver from django.contrib.auth.models import User import logging -from .tasks import update_jabber_groups -from .tasks import update_mumble_groups -from .tasks import update_forum_groups -from .tasks import update_ipboard_groups -from .tasks import update_discord_groups -from .tasks import update_teamspeak3_groups -from .tasks import update_discourse_groups -from .tasks import update_smf_groups -from .tasks import set_state -from .tasks import disable_member +from services.tasks import update_jabber_groups +from services.tasks import update_mumble_groups +from services.tasks import update_forum_groups +from services.tasks import update_ipboard_groups +from services.tasks import update_discord_groups +from services.tasks import update_teamspeak3_groups +from services.tasks import update_discourse_groups +from services.tasks import update_smf_groups +from authentication.tasks import set_state +from authentication.tasks import disable_member from authentication.models import AuthServicesInfo from services.models import AuthTS logger = logging.getLogger(__name__) + @receiver(m2m_changed, sender=User.groups.through) def m2m_changed_user_groups(sender, instance, action, *args, **kwargs): logger.debug("Received m2m_changed from %s groups with action %s" % (instance, action)) - if action=="post_add" or action=="post_remove" or action=="post_clear": + if action == "post_add" or action == "post_remove" or action == "post_clear": logger.debug("Triggering service group update for %s" % instance) auth, c = AuthServicesInfo.objects.get_or_create(user=instance) if auth.jabber_username: @@ -43,32 +45,40 @@ def m2m_changed_user_groups(sender, instance, action, *args, **kwargs): update_mumble_groups.delay(instance.pk) if auth.discourse_username: update_discourse_groups.delay(instance.pk) + if auth.smf_username: + update_smf_groups.delay(instance.pk) + def trigger_all_ts_update(): for auth in AuthServicesInfo.objects.filter(teamspeak3_uid__isnull=False): update_teamspeak3_groups.delay(auth.user.pk) + @receiver(m2m_changed, sender=AuthTS.ts_group.through) def m2m_changed_authts_group(sender, instance, action, *args, **kwargs): logger.debug("Received m2m_changed from %s ts_group with action %s" % (instance, action)) - if action=="post_add" or action=="post_remove": + if action == "post_add" or action == "post_remove": trigger_all_ts_update() + @receiver(post_save, sender=AuthTS) def post_save_authts(sender, instance, *args, **kwargs): logger.debug("Received post_save from %s" % instance) trigger_all_ts_update() + @receiver(post_delete, sender=AuthTS) def post_delete_authts(sender, instance, *args, **kwargs): logger.debug("Received post_delete signal from %s" % instance) trigger_all_ts_update() + @receiver(pre_delete, sender=User) def pre_delete_user(sender, instance, *args, **kwargs): logger.debug("Received pre_delete from %s" % instance) disable_member(instance) + @receiver(pre_save, sender=User) def pre_save_user(sender, instance, *args, **kwargs): logger.debug("Received pre_save from %s" % instance) diff --git a/services/tasks.py b/services/tasks.py index e3a45694..e754de13 100644 --- a/services/tasks.py +++ b/services/tasks.py @@ -1,20 +1,47 @@ -from authentication.models import AuthServicesInfo -from celerytask.models import SyncGroupCache +from __future__ import unicode_literals from django.conf import settings import logging +from django.contrib.auth.models import User +from celery import task from services.models import UserTSgroup from services.models import AuthTS from services.models import TSgroup -from services.models import DiscordAuthToken from services.models import MumbleUser +from authentication.managers import AuthServicesInfoManager +from authentication.models import AuthServicesInfo +from services.managers.openfire_manager import OpenfireManager +from services.managers.phpbb3_manager import Phpbb3Manager +from services.managers.mumble_manager import MumbleManager +from services.managers.ipboard_manager import IPBoardManager +from services.managers.teamspeak3_manager import Teamspeak3Manager +from services.managers.discord_manager import DiscordOAuthManager +from services.managers.xenforo_manager import XenForoManager +from services.managers.market_manager import marketManager +from services.managers.discourse_manager import DiscourseManager +from services.managers.smf_manager import smfManager +from services.managers.util.ts3 import TeamspeakError +from authentication.states import MEMBER_STATE, BLUE_STATE +from notifications import notify +from celery.task import periodic_task +from celery.task.schedules import crontab logger = logging.getLogger(__name__) + +@periodic_task(run_every=crontab(minute="*/30")) +def run_ts3_group_update(): + if settings.ENABLE_AUTH_TEAMSPEAK3 or settings.ENABLE_BLUE_TEAMSPEAK3: + logger.debug("TS3 installed. Syncing local group objects.") + Teamspeak3Manager._sync_ts_group_db() + + def disable_teamspeak(): if settings.ENABLE_AUTH_TEAMSPEAK3: - logger.warn("ENABLE_AUTH_TEAMSPEAK3 still True, after disabling users will still be able to create teamspeak accounts") + logger.warn( + "ENABLE_AUTH_TEAMSPEAK3 still True, after disabling users will still be able to create teamspeak accounts") if settings.ENABLE_BLUE_TEAMSPEAK3: - logger.warn("ENABLE_BLUE_TEAMSPEAK3 still True, after disabling blues will still be able to create teamspeak accounts") + logger.warn( + "ENABLE_BLUE_TEAMSPEAK3 still True, after disabling blues will still be able to create teamspeak accounts") for auth in AuthServicesInfo.objects.all(): if auth.teamspeak3_uid: logger.info("Clearing %s Teamspeak3 UID" % auth.user) @@ -32,6 +59,7 @@ def disable_teamspeak(): TSgroup.objects.all().delete() logger.info("Teamspeak3 disabled") + def disable_forum(): if settings.ENABLE_AUTH_FORUM: logger.warn("ENABLE_AUTH_FORUM still True, after disabling users will still be able to create forum accounts") @@ -46,8 +74,7 @@ def disable_forum(): logger.info("Clearing %s forum password" % auth.user) auth.forum_password = '' auth.save() - logger.info("Deleting all SyncGroupCache models for forum") - SyncGroupCache.objects.filter(servicename="forum").delete() + def disable_jabber(): if settings.ENABLE_AUTH_JABBER: @@ -63,8 +90,7 @@ def disable_jabber(): logger.info("Clearing %s jabber password" % auth.user) auth.jabber_password = '' auth.save() - logger.info("Deleting all SyncGroupCache models for jabber") - SyncGroupCache.objects.filter(servicename="jabber").delete() + def disable_mumble(): if settings.ENABLE_AUTH_MUMBLE: @@ -80,16 +106,17 @@ def disable_mumble(): logger.info("Clearing %s mumble password" % auth.user) auth.mumble_password = '' auth.save() - logger.info("Deleting all SyncGroupCache models for mumble") - SyncGroupCache.objects.filter(servicename="mumble").delete() logger.info("Deleting all MumbleUser models") MumbleUser.objects.all().delete() + def disable_ipboard(): if settings.ENABLE_AUTH_IPBOARD: - logger.warn("ENABLE_AUTH_IPBOARD still True, after disabling users will still be able to create IPBoard accounts") + logger.warn( + "ENABLE_AUTH_IPBOARD still True, after disabling users will still be able to create IPBoard accounts") if settings.ENABLE_BLUE_IPBOARD: - logger.warn("ENABLE_BLUE_IPBOARD still True, after disabling blues will still be able to create IPBoard accounts") + logger.warn( + "ENABLE_BLUE_IPBOARD still True, after disabling blues will still be able to create IPBoard accounts") for auth in AuthServicesInfo.objects.all(): if auth.ipboard_username: logger.info("Clearing %s ipboard username" % auth.user) @@ -99,8 +126,6 @@ def disable_ipboard(): logger.info("Clearing %s ipboard password" % auth.user) auth.ipboard_password = '' auth.save() - logger.info("Deleting all SyncGroupCache models for ipboard") - SyncGroupCache.objects.filter(servicename="ipboard").delete() def disable_discord(): @@ -113,5 +138,349 @@ def disable_discord(): logger.info("Clearing %s Discord UID" % auth.user) auth.discord_uid = '' auth.save() - logger.info("Deleting all DiscordAuthToken models") - DiscordAuthToken.objects.all().delete() + + +def deactivate_services(user): + change = False + logger.debug("Deactivating services for user %s" % user) + authinfo = AuthServicesInfo.objects.get_or_create(user=user)[0] + if authinfo.mumble_username and authinfo.mumble_username != "": + logger.debug("User %s has mumble account %s. Deleting." % (user, authinfo.mumble_username)) + MumbleManager.delete_user(authinfo.mumble_username) + AuthServicesInfoManager.update_user_mumble_info("", user) + change = True + if authinfo.jabber_username and authinfo.jabber_username != "": + logger.debug("User %s has jabber account %s. Deleting." % (user, authinfo.jabber_username)) + OpenfireManager.delete_user(authinfo.jabber_username) + AuthServicesInfoManager.update_user_jabber_info("", user) + change = True + if authinfo.forum_username and authinfo.forum_username != "": + logger.debug("User %s has forum account %s. Deleting." % (user, authinfo.forum_username)) + Phpbb3Manager.disable_user(authinfo.forum_username) + AuthServicesInfoManager.update_user_forum_info("", user) + change = True + if authinfo.ipboard_username and authinfo.ipboard_username != "": + logger.debug("User %s has ipboard account %s. Deleting." % (user, authinfo.ipboard_username)) + IPBoardManager.disable_user(authinfo.ipboard_username) + AuthServicesInfoManager.update_user_ipboard_info("", user) + change = True + if authinfo.teamspeak3_uid and authinfo.teamspeak3_uid != "": + logger.debug("User %s has mumble account %s. Deleting." % (user, authinfo.teamspeak3_uid)) + Teamspeak3Manager.delete_user(authinfo.teamspeak3_uid) + AuthServicesInfoManager.update_user_teamspeak3_info("", "", user) + change = True + if authinfo.discord_uid and authinfo.discord_uid != "": + logger.debug("User %s has discord account %s. Deleting." % (user, authinfo.discord_uid)) + DiscordOAuthManager.delete_user(authinfo.discord_uid) + AuthServicesInfoManager.update_user_discord_info("", user) + change = True + if authinfo.xenforo_username and authinfo.xenforo_password != "": + logger.debug("User %s has a XenForo account %s. Deleting." % (user, authinfo.xenforo_username)) + XenForoManager.disable_user(authinfo.xenforo_username) + AuthServicesInfoManager.update_user_xenforo_info("", user) + change = True + if authinfo.market_username and authinfo.market_username != "": + logger.debug("User %s has a Market account %s. Deleting." % (user, authinfo.market_username)) + marketManager.disable_user(authinfo.market_username) + AuthServicesInfoManager.update_user_market_info("", user) + change = True + if authinfo.discourse_username and authinfo.discourse_username != "": + logger.debug("User %s has a Discourse account %s. Deleting." % (user, authinfo.discourse_username)) + DiscourseManager.delete_user(authinfo.discourse_username) + AuthServicesInfoManager.update_user_discourse_info("", user) + change = True + if authinfo.smf_username and authinfo.smf_username != "": + logger.debug("User %s has a SMF account %s. Deleting." % (user, authinfo.smf_username)) + smfManager.disable_user(authinfo.smf_username) + AuthServicesInfoManager.update_user_smf_info("", user) + change = True + if change: + notify(user, "Services Disabled", message="Your services accounts have been disabled.", level="danger") + + +@task +def validate_services(user, state): + if state == MEMBER_STATE: + setting_string = 'AUTH' + elif state == BLUE_STATE: + setting_string = 'BLUE' + else: + deactivate_services(user) + return + logger.debug('Ensuring user %s services are available to state %s' % (user, state)) + auth = AuthServicesInfo.objects.get_or_create(user=user)[0] + if auth.mumble_username and not getattr(settings, 'ENABLE_%s_MUMBLE' % setting_string, False): + MumbleManager.delete_user(auth.mumble_username) + AuthServicesInfoManager.update_user_mumble_info("", user) + notify(user, 'Mumble Account Disabled', level='danger') + if auth.jabber_username and not getattr(settings, 'ENABLE_%s_JABBER' % setting_string, False): + OpenfireManager.delete_user(auth.jabber_username) + AuthServicesInfoManager.update_user_jabber_info("", user) + notify(user, 'Jabber Account Disabled', level='danger') + if auth.forum_username and not getattr(settings, 'ENABLE_%s_FORUM' % setting_string, False): + Phpbb3Manager.disable_user(auth.forum_username) + AuthServicesInfoManager.update_user_forum_info("", user) + notify(user, 'Forum Account Disabled', level='danger') + if auth.ipboard_username and not getattr(settings, 'ENABLE_%s_IPBOARD' % setting_string, False): + IPBoardManager.disable_user(auth.ipboard_username) + AuthServicesInfoManager.update_user_ipboard_info("", user) + notify(user, 'IPBoard Account Disabled', level='danger') + if auth.teamspeak3_uid and not getattr(settings, 'ENABLE_%s_TEAMSPEAK' % setting_string, False): + Teamspeak3Manager.delete_user(auth.teamspeak3_uid) + AuthServicesInfoManager.update_user_teamspeak3_info("", "", user) + notify(user, 'TeamSpeak3 Account Disabled', level='danger') + if auth.discord_uid and not getattr(settings, 'ENABLE_%s_DISCORD' % setting_string, False): + DiscordOAuthManager.delete_user(auth.discord_uid) + AuthServicesInfoManager.update_user_discord_info("", user) + notify(user, 'Discord Account Disabled', level='danger') + if auth.xenforo_username and not getattr(settings, 'ENABLE_%s_XENFORO' % setting_string, False): + XenForoManager.disable_user(auth.xenforo_username) + AuthServicesInfoManager.update_user_xenforo_info("", user) + notify(user, 'XenForo Account Disabled', level='danger') + if auth.market_username and not getattr(settings, 'ENABLE_%s_MARKET' % setting_string, False): + marketManager.disable_user(auth.market_username) + AuthServicesInfoManager.update_user_market_info("", user) + notify(user, 'Alliance Market Account Disabled', level='danger') + if auth.discourse_username and not getattr(settings, 'ENABLE_%s_DISCOURSE' % setting_string, False): + DiscourseManager.delete_user(auth.discourse_username) + AuthServicesInfoManager.update_user_discourse_info("", user) + notify(user, 'Discourse Account Disabled', level='danger') + if auth.smf_username and not getattr(settings, 'ENABLE_%s_SMF' % setting_string, False): + smfManager.disable_user(auth.smf_username) + AuthServicesInfoManager.update_user_smf_info(auth.smf_username, user) + notify(user, "SMF Account Disabled", level='danger') + + +@task +def update_jabber_groups(pk): + user = User.objects.get(pk=pk) + logger.debug("Updating jabber groups for user %s" % user) + authserviceinfo = AuthServicesInfo.objects.get(user=user) + groups = [] + for group in user.groups.all(): + groups.append(str(group.name)) + if len(groups) == 0: + groups.append('empty') + logger.debug("Updating user %s jabber groups to %s" % (user, groups)) + try: + OpenfireManager.update_user_groups(authserviceinfo.jabber_username, groups) + except: + logger.exception("Jabber group sync failed for %s, retrying in 10 mins" % user) + raise self.retry(countdown=60 * 10) + logger.debug("Updated user %s jabber groups." % user) + + +@task +def update_all_jabber_groups(): + logger.debug("Updating ALL jabber groups") + for user in AuthServicesInfo.objects.exclude(jabber_username__exact=''): + update_jabber_groups.delay(user.user_id) + + +@task +def update_mumble_groups(pk): + user = User.objects.get(pk=pk) + logger.debug("Updating mumble groups for user %s" % user) + authserviceinfo = AuthServicesInfo.objects.get(user=user) + groups = [] + for group in user.groups.all(): + groups.append(str(group.name)) + if len(groups) == 0: + groups.append('empty') + logger.debug("Updating user %s mumble groups to %s" % (user, groups)) + try: + MumbleManager.update_groups(authserviceinfo.mumble_username, groups) + except: + logger.exception("Mumble group sync failed for %s, retrying in 10 mins" % user) + raise self.retry(countdown=60 * 10) + logger.debug("Updated user %s mumble groups." % user) + + +@task +def update_all_mumble_groups(): + logger.debug("Updating ALL mumble groups") + for user in AuthServicesInfo.objects.exclude(mumble_username__exact=''): + update_mumble_groups.delay(user.user_id) + + +@task +def update_forum_groups(pk): + user = User.objects.get(pk=pk) + logger.debug("Updating forum groups for user %s" % user) + authserviceinfo = AuthServicesInfo.objects.get(user=user) + groups = [] + for group in user.groups.all(): + groups.append(str(group.name)) + if len(groups) == 0: + groups.append('empty') + logger.debug("Updating user %s forum groups to %s" % (user, groups)) + try: + Phpbb3Manager.update_groups(authserviceinfo.forum_username, groups) + except: + logger.exception("Phpbb group sync failed for %s, retrying in 10 mins" % user) + raise self.retry(countdown=60 * 10) + logger.debug("Updated user %s forum groups." % user) + + +@task +def update_all_forum_groups(): + logger.debug("Updating ALL forum groups") + for user in AuthServicesInfo.objects.exclude(forum_username__exact=''): + update_forum_groups.delay(user.user_id) + + +@task +def update_smf_groups(pk): + user = User.objects.get(pk=pk) + logger.debug("Updating smf groups for user %s" % user) + authserviceinfo = AuthServicesInfo.objects.get(user=user) + groups = [] + for group in user.groups.all(): + groups.append(str(group.name)) + if len(groups) == 0: + groups.append('empty') + logger.debug("Updating user %s smf groups to %s" % (user, groups)) + try: + smfManager.update_groups(authserviceinfo.smf_username, groups) + except: + logger.exception("smf group sync failed for %s, retrying in 10 mins" % user) + raise self.retry(countdown=60 * 10) + logger.debug("Updated user %s smf groups." % user) + + +@task +def update_all_smf_groups(): + logger.debug("Updating ALL smf groups") + for user in AuthServicesInfo.objects.exclude(smf_username__exact=''): + update_smf_groups.delay(user.user_id) + + +@task +def update_ipboard_groups(pk): + user = User.objects.get(pk=pk) + logger.debug("Updating user %s ipboard groups." % user) + authserviceinfo = AuthServicesInfo.objects.get(user=user) + groups = [] + for group in user.groups.all(): + groups.append(str(group.name)) + if len(groups) == 0: + groups.append('empty') + logger.debug("Updating user %s ipboard groups to %s" % (user, groups)) + try: + IPBoardManager.update_groups(authserviceinfo.ipboard_username, groups) + except: + logger.exception("IPBoard group sync failed for %s, retrying in 10 mins" % user) + raise self.retry(countdown=60 * 10) + logger.debug("Updated user %s ipboard groups." % user) + + +@task +def update_all_ipboard_groups(): + logger.debug("Updating ALL ipboard groups") + for user in AuthServicesInfo.objects.exclude(ipboard_username__exact=''): + update_ipboard_groups.delay(user.user_id) + + +@task +def update_teamspeak3_groups(pk): + user = User.objects.get(pk=pk) + logger.debug("Updating user %s teamspeak3 groups" % user) + usergroups = user.groups.all() + authserviceinfo = AuthServicesInfo.objects.get(user=user) + groups = {} + for usergroup in usergroups: + filtered_groups = AuthTS.objects.filter(auth_group=usergroup) + if filtered_groups: + for filtered_group in filtered_groups: + for ts_group in filtered_group.ts_group.all(): + groups[ts_group.ts_group_name] = ts_group.ts_group_id + logger.debug("Updating user %s teamspeak3 groups to %s" % (user, groups)) + try: + Teamspeak3Manager.update_groups(authserviceinfo.teamspeak3_uid, groups) + logger.debug("Updated user %s teamspeak3 groups." % user) + except TeamspeakError as e: + logger.error("Error occured while syncing TS groups for %s: %s" % (user, str(e))) + raise self.retry(countdown=60*10) + + +@task +def update_all_teamspeak3_groups(): + logger.debug("Updating ALL teamspeak3 groups") + for user in AuthServicesInfo.objects.exclude(teamspeak3_uid__exact=''): + update_teamspeak3_groups.delay(user.user_id) + + +@task +def update_discord_groups(pk): + user = User.objects.get(pk=pk) + logger.debug("Updating discord groups for user %s" % user) + authserviceinfo = AuthServicesInfo.objects.get(user=user) + groups = [] + for group in user.groups.all(): + groups.append(str(group.name)) + if len(groups) == 0: + logger.debug("No syncgroups found for user. Adding empty group.") + groups.append('empty') + logger.debug("Updating user %s discord groups to %s" % (user, groups)) + try: + DiscordOAuthManager.update_groups(authserviceinfo.discord_uid, groups) + except: + logger.exception("Discord group sync failed for %s, retrying in 10 mins" % user) + raise self.retry(countdown=60 * 10) + logger.debug("Updated user %s discord groups." % user) + + +@task +def update_all_discord_groups(): + logger.debug("Updating ALL discord groups") + for user in AuthServicesInfo.objects.exclude(discord_uid__exact=''): + update_discord_groups.delay(user.user_id) + + +@task +def update_discord_nickname(pk): + user = User.objects.get(pk=pk) + logger.debug("Updating discord nickname for user %s" % user) + authserviceinfo = AuthServicesInfo.objects.get(user=user) + character = EveManager.get_character_by_id(authserviceinfo.main_char_id) + logger.debug("Updating user %s discord nickname to %s" % (user, character.character_name)) + try: + DiscordOAuthManager.update_nickname(authserviceinfo.discord_uid, character.character_name) + except: + logger.exception("Discord nickname sync failed for %s, retrying in 10 mins" % user) + raise self.retry(countdown=60 * 10) + logger.debug("Updated user %s discord nickname." % user) + + +@task +def update_all_discord_nicknames(): + logger.debug("Updating ALL discord nicknames") + for user in AuthServicesInfo.objects.exclude(discord_uid__exact=''): + update_discord_nickname(user.user_id) + + +@task +def update_discourse_groups(pk): + user = User.objects.get(pk=pk) + logger.debug("Updating discourse groups for user %s" % user) + authserviceinfo = AuthServicesInfo.objects.get(user=user) + groups = [] + for group in user.groups.all(): + groups.append(str(group.name)) + if len(groups) == 0: + logger.debug("No syncgroups found for user. Adding empty group.") + groups.append('empty') + logger.debug("Updating user %s discourse groups to %s" % (user, groups)) + try: + DiscourseManager.update_groups(authserviceinfo.discourse_username, groups) + except: + logger.warn("Discourse group sync failed for %s, retrying in 10 mins" % user, exc_info=True) + raise self.retry(countdown=60 * 10) + logger.debug("Updated user %s discourse groups." % user) + + +@task +def update_all_discourse_groups(): + logger.debug("Updating ALL discourse groups") + for user in AuthServicesInfo.objects.exclude(discourse_username__exact=''): + update_discourse_groups.delay(user.user_id) diff --git a/services/views.py b/services/views.py index f931ab8f..79ba8cf4 100755 --- a/services/views.py +++ b/services/views.py @@ -1,52 +1,50 @@ -from django.template import RequestContext -from django.shortcuts import HttpResponseRedirect -from django.shortcuts import render_to_response +from __future__ import unicode_literals +from django.shortcuts import render, redirect from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import permission_required from django.contrib.auth.decorators import user_passes_test from django.contrib.auth.models import Group from django.conf import settings - +from django.contrib import messages from eveonline.models import EveCharacter from eveonline.models import EveAllianceInfo from authentication.models import AuthServicesInfo -from managers.openfire_manager import OpenfireManager -from managers.phpbb3_manager import Phpbb3Manager -from managers.mumble_manager import MumbleManager -from managers.ipboard_manager import IPBoardManager -from managers.xenforo_manager import XenForoManager -from managers.teamspeak3_manager import Teamspeak3Manager -from managers.discord_manager import DiscordOAuthManager -from managers.discourse_manager import DiscourseManager -from managers.ips4_manager import Ips4Manager -from managers.smf_manager import smfManager -from managers.market_manager import marketManager -from managers.pathfinder_manager import pathfinderManager +from services.managers.openfire_manager import OpenfireManager +from services.managers.phpbb3_manager import Phpbb3Manager +from services.managers.mumble_manager import MumbleManager +from services.managers.ipboard_manager import IPBoardManager +from services.managers.xenforo_manager import XenForoManager +from services.managers.teamspeak3_manager import Teamspeak3Manager +from services.managers.discord_manager import DiscordOAuthManager +from services.managers.discourse_manager import DiscourseManager +from services.managers.ips4_manager import Ips4Manager +from services.managers.smf_manager import smfManager +from services.managers.market_manager import marketManager from authentication.managers import AuthServicesInfoManager from eveonline.managers import EveManager -from celerytask.tasks import update_jabber_groups -from celerytask.tasks import update_mumble_groups -from celerytask.tasks import update_forum_groups -from celerytask.tasks import update_ipboard_groups -from celerytask.tasks import update_smf_groups -from celerytask.tasks import update_teamspeak3_groups -from celerytask.tasks import update_discord_groups -from celerytask.tasks import update_discord_nickname -from celerytask.tasks import update_discourse_groups -from forms import JabberBroadcastForm -from forms import FleetFormatterForm -from forms import DiscordForm -from forms import ServicePasswordForm -from forms import TeamspeakJoinForm -from util import check_if_user_has_permission +from services.tasks import update_jabber_groups +from services.tasks import update_mumble_groups +from services.tasks import update_forum_groups +from services.tasks import update_ipboard_groups +from services.tasks import update_smf_groups +from services.tasks import update_teamspeak3_groups +from services.tasks import update_discord_groups +from services.tasks import update_discord_nickname +from services.tasks import update_discourse_groups +from services.forms import JabberBroadcastForm +from services.forms import FleetFormatterForm +from services.forms import ServicePasswordForm +from services.forms import TeamspeakJoinForm +from authentication.decorators import members_and_blues +from authentication.states import MEMBER_STATE, BLUE_STATE -import threading -import datetime +import datetime import logging logger = logging.getLogger(__name__) + @login_required def fleet_formatter_view(request): logger.debug("fleet_formatter_view called by user %s" % request.user) @@ -74,15 +72,15 @@ def fleet_formatter_view(request): context = {'form': form, 'generated': generated} - return render_to_response('registered/fleetformattertool.html', context, context_instance=RequestContext(request)) + return render(request, 'registered/fleetformattertool.html', context=context) + @login_required @permission_required('auth.jabber_broadcast') def jabber_broadcast_view(request): logger.debug("jabber_broadcast_view called by user %s" % request.user) - success = False allchoices = [] - if check_if_user_has_permission(request.user, 'jabber_broadcast_all'): + if request.user.has_perm('auth.jabber_broadcast_all'): allchoices.append(('all', 'all')) for g in Group.objects.all(): allchoices.append((str(g.name), str(g.name))) @@ -98,140 +96,204 @@ def jabber_broadcast_view(request): main_char = EveCharacter.objects.get(character_id=user_info.main_char_id) logger.debug("Processing jabber broadcast for user %s with main character %s" % (user_info, main_char)) if user_info.main_char_id != "": - message_to_send = form.cleaned_data['message'] + "\n##### SENT BY: " + "[" + main_char.corporation_ticker + "]" + main_char.character_name + " TO: " + form.cleaned_data['group'] + " WHEN: " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S") + " #####\n##### Replies are NOT monitored #####\n" + message_to_send = form.cleaned_data[ + 'message'] + "\n##### SENT BY: " + "[" + main_char.corporation_ticker + "]" + \ + main_char.character_name + " TO: " + \ + form.cleaned_data['group'] + " WHEN: " + datetime.datetime.utcnow().strftime( + "%Y-%m-%d %H:%M:%S") + " #####\n##### Replies are NOT monitored #####\n" group_to_send = form.cleaned_data['group'] - OpenfireManager.send_broadcast_threaded(group_to_send, message_to_send,) + OpenfireManager.send_broadcast_threaded(group_to_send, message_to_send, ) else: - message_to_send = form.cleaned_data['message'] + "\n##### SENT BY: " + "No character but can send pings?" + " TO: " + form.cleaned_data['group'] + " WHEN: " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S") + " #####\n##### Replies are NOT monitored #####\n" + message_to_send = form.cleaned_data[ + 'message'] + "\n##### SENT BY: " + "No character but can send pings?" + " TO: " + \ + form.cleaned_data['group'] + " WHEN: " + datetime.datetime.utcnow().strftime( + "%Y-%m-%d %H:%M:%S") + " #####\n##### Replies are NOT monitored #####\n" group_to_send = form.cleaned_data['group'] - OpenfireManager.send_broadcast_threaded(group_to_send, message_to_send,) + OpenfireManager.send_broadcast_threaded(group_to_send, message_to_send, ) - success = True + messages.success(request, 'Sent jabber broadcast to %s' % group_to_send) logger.info("Sent jabber broadcast on behalf of user %s" % request.user) else: form = JabberBroadcastForm() form.fields['group'].choices = allchoices - logger.debug("Generated broadcast form for user %s containing %s groups" % (request.user, len(form.fields['group'].choices))) + logger.debug("Generated broadcast form for user %s containing %s groups" % ( + request.user, len(form.fields['group'].choices))) - context = {'form': form, 'success': success} - return render_to_response('registered/jabberbroadcast.html', context, context_instance=RequestContext(request)) + context = {'form': form} + return render(request, 'registered/jabberbroadcast.html', context=context) @login_required +@members_and_blues() def services_view(request): logger.debug("services_view called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + auth = AuthServicesInfo.objects.get_or_create(user=request.user)[0] - return render_to_response('registered/services.html', {'authinfo': authinfo}, - context_instance=RequestContext(request)) + services = [ + 'FORUM', + 'JABBER', + 'MUMBLE', + 'IPBOARD', + 'TEAMSPEAK3', + 'DISCORD', + 'DISCOURSE', + 'IPS4', + 'SMF', + 'MARKET', + 'XENFORO', + ] + context = {'authinfo': auth} + + for s in services: + context['SHOW_' + s] = (getattr(settings, 'ENABLE_AUTH_' + s) and ( + auth.state == MEMBER_STATE or request.user.is_superuser)) or (getattr(settings, 'ENABLE_BLUE_' + s) and ( + auth.state == BLUE_STATE or request.user.is_superuser)) + + return render(request, 'registered/services.html', context=context) -def service_blue_alliance_test(user): - return check_if_user_has_permission(user, 'member') or check_if_user_has_permission(user, 'blue_member') def superuser_test(user): return user.is_superuser + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def activate_forum(request): logger.debug("activate_forum called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] # Valid now we get the main characters character = EveManager.get_character_by_id(authinfo.main_char_id) logger.debug("Adding phpbb user for user %s with main character %s" % (request.user, character)) result = Phpbb3Manager.add_user(character.character_name, request.user.email, ['REGISTERED'], authinfo.main_char_id) # if empty we failed if result[0] != "": - AuthServicesInfoManager.update_user_forum_info(result[0], result[1], request.user) + AuthServicesInfoManager.update_user_forum_info(result[0], request.user) logger.debug("Updated authserviceinfo for user %s with forum credentials. Updating groups." % request.user) update_forum_groups.delay(request.user.pk) - logger.info("Succesfully activated forum for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccesful attempt to activate forum for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + logger.info("Successfully activated forum for user %s" % request.user) + messages.success(request, 'Activated forum account.') + credentials = { + 'username': result[0], + 'password': result[1], + } + return render(request, 'registered/service_credentials.html', + context={'credentials': credentials, 'service': 'Forum'}) + else: + logger.error("Unsuccessful attempt to activate forum for user %s" % request.user) + messages.error(request, 'An error occurred while processing your forum account.') + return redirect("auth_services") @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def deactivate_forum(request): logger.debug("deactivate_forum called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = Phpbb3Manager.disable_user(authinfo.forum_username) # false we failed if result: - AuthServicesInfoManager.update_user_forum_info("", "", request.user) - logger.info("Succesfully deactivated forum for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccesful attempt to activate forum for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + AuthServicesInfoManager.update_user_forum_info("", request.user) + logger.info("Successfully deactivated forum for user %s" % request.user) + messages.success(request, 'Deactivated forum account.') + else: + logger.error("Unsuccessful attempt to activate forum for user %s" % request.user) + messages.error(request, 'An error occurred while processing your forum account.') + return redirect("auth_services") @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def reset_forum_password(request): logger.debug("reset_forum_password called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = Phpbb3Manager.update_user_password(authinfo.forum_username, authinfo.main_char_id) # false we failed if result != "": - AuthServicesInfoManager.update_user_forum_info(authinfo.forum_username, result, request.user) - logger.info("Succesfully reset forum password for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccessful attempt to reset forum password for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + logger.info("Successfully reset forum password for user %s" % request.user) + messages.success(request, 'Reset forum password.') + credentials = { + 'username': authinfo.forum_username, + 'password': result, + } + return render(request, 'registered/service_credentials.html', + context={'credentials': credentials, 'service': 'Forum'}) + else: + logger.error("Unsuccessful attempt to reset forum password for user %s" % request.user) + messages.error(request, 'An error occurred while processing your forum account.') + return redirect("auth_services") + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def activate_xenforo_forum(request): logger.debug("activate_xenforo_forum called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] character = EveManager.get_character_by_id(authinfo.main_char_id) logger.debug("Adding XenForo user for user %s with main character %s" % (request.user, character)) result = XenForoManager.add_user(character.character_name, request.user.email) # Based on XenAPI's response codes if result['response']['status_code'] == 200: logger.info("Updated authserviceinfo for user %s with XenForo credentials. Updating groups." % request.user) - AuthServicesInfoManager.update_user_xenforo_info(result['username'], result['password'], request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccesful attempt to activate xenforo for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + AuthServicesInfoManager.update_user_xenforo_info(result['username'], request.user) + messages.success(request, 'Activated XenForo account.') + credentials = { + 'username': result['username'], + 'password': result['password'], + } + return render(request, 'registered/service_credentials.html', + context={'credentials': credentials, 'service': 'XenForo'}) + + else: + logger.error("UnSuccessful attempt to activate xenforo for user %s" % request.user) + messages.error(request, 'An error occurred while processing your XenForo account.') + return redirect("auth_services") + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def deactivate_xenforo_forum(request): logger.debug("deactivate_xenforo_forum called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = XenForoManager.disable_user(authinfo.xenforo_username) if result.status_code == 200: - AuthServicesInfoManager.update_user_xenforo_info("", "", request.user) - logger.info("Succesfully deactivated XenForo for user %s" % request.user) - return HttpResponseRedirect("/services/") - return HttpResponseRedirect("/dashboard") + AuthServicesInfoManager.update_user_xenforo_info("", request.user) + logger.info("Successfully deactivated XenForo for user %s" % request.user) + messages.success(request, 'Deactivated XenForo account.') + else: + messages.error(request, 'An error occurred while processing your XenForo account.') + return redirect("auth_services") + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def reset_xenforo_password(request): logger.debug("reset_xenforo_password called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) - character = EveManager.get_character_by_id(authinfo.main_char_id) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = XenForoManager.reset_password(authinfo.xenforo_username) # Based on XenAPI's response codes if result['response']['status_code'] == 200: - AuthServicesInfoManager.update_user_xenforo_info(authinfo.xenforo_username, result['password'], request.user) - logger.info("Succesfully reset XenForo password for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccessful attempt to reset XenForo password for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + logger.info("Successfully reset XenForo password for user %s" % request.user) + messages.success(request, 'Reset XenForo account password.') + credentials = { + 'username': authinfo.xenforo_username, + 'password': result['password'], + } + return render(request, 'registered/service_credentials.html', + context={'credentials': credentials, 'service': 'XenForo'}) + else: + logger.error("Unsuccessful attempt to reset XenForo password for user %s" % request.user) + messages.error(request, 'An error occurred while processing your XenForo account.') + return redirect("auth_services") + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def set_xenforo_password(request): logger.debug("set_xenforo_password called by user %s" % request.user) - error = None if request.method == 'POST': logger.debug("Received POST request with form.") form = ServicePasswordForm(request.POST) @@ -239,131 +301,165 @@ def set_xenforo_password(request): if form.is_valid(): password = form.cleaned_data['password'] logger.debug("Form contains password of length %s" % len(password)) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = XenForoManager.update_user_password(authinfo.xenforo_username, password) if result['response']['status_code'] == 200: - AuthServicesInfoManager.update_user_xenforo_info(authinfo.xenforo_username, result['password'], request.user) - logger.info("Succesfully reset XenForo password for user %s" % request.user) - return HttpResponseRedirect("/services/") + logger.info("Successfully reset XenForo password for user %s" % request.user) + messages.success(request, 'Changed XenForo password.') else: logger.error("Failed to install custom XenForo password for user %s" % request.user) - error = "Failed to install custom password." - else: - error = "Invalid password provided" + messages.error(request, 'An error occurred while processing your XenForo account.') + return redirect('auth_services') else: logger.debug("Request is not type POST - providing empty form.") form = ServicePasswordForm() logger.debug("Rendering form for user %s" % request.user) context = {'form': form, 'service': 'Forum'} - return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) + return render(request, 'registered/service_password.html', context=context) + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def activate_ipboard_forum(request): logger.debug("activate_ipboard_forum called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] # Valid now we get the main characters character = EveManager.get_character_by_id(authinfo.main_char_id) logger.debug("Adding ipboard user for user %s with main character %s" % (request.user, character)) result = IPBoardManager.add_user(character.character_name, request.user.email) if result[0] != "": - AuthServicesInfoManager.update_user_ipboard_info(result[0], result[1], request.user) + AuthServicesInfoManager.update_user_ipboard_info(result[0], request.user) logger.debug("Updated authserviceinfo for user %s with ipboard credentials. Updating groups." % request.user) update_ipboard_groups.delay(request.user.pk) - logger.info("Succesfully activated ipboard for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccesful attempt to activate ipboard for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + logger.info("Successfully activated ipboard for user %s" % request.user) + messages.success(request, 'Activated IPBoard account.') + credentials = { + 'username': result[0], + 'password': result[1], + } + return render(request, 'registered/service_credentials.html', + context={'credentials': credentials, 'service': 'IPBoard'}) + else: + logger.error("UnSuccessful attempt to activate ipboard for user %s" % request.user) + messages.error(request, 'An error occurred while processing your IPBoard account.') + return redirect("auth_services") @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def deactivate_ipboard_forum(request): logger.debug("deactivate_ipboard_forum called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = IPBoardManager.disable_user(authinfo.ipboard_username) # false we failed if result: - AuthServicesInfoManager.update_user_ipboard_info("", "", request.user) - logger.info("Succesfully deactivated ipboard for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccessful attempt to deactviate ipboard for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + AuthServicesInfoManager.update_user_ipboard_info("", request.user) + logger.info("Successfully deactivated ipboard for user %s" % request.user) + messages.success(request, 'Deactivated IPBoard account.') + else: + logger.error("Unsuccessful attempt to deactviate ipboard for user %s" % request.user) + messages.error(request, 'An error occurred while processing your IPBoard account.') + return redirect("auth_services") @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def reset_ipboard_password(request): logger.debug("reset_ipboard_password called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = IPBoardManager.update_user_password(authinfo.ipboard_username, request.user.email) if result != "": - AuthServicesInfoManager.update_user_ipboard_info(authinfo.ipboard_username, result, request.user) - logger.info("Succesfully reset ipboard password for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccesful attempt to reset ipboard password for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + logger.info("Successfully reset ipboard password for user %s" % request.user) + messages.success(request, 'Reset IPBoard password.') + credentials = { + 'username': authinfo.ipboard_username, + 'password': result, + } + return render(request, 'registered/service_credentials.html', + context={'credentials': credentials, 'service': 'IPBoard'}) + else: + logger.error("UnSuccessful attempt to reset ipboard password for user %s" % request.user) + messages.error(request, 'An error occurred while processing your IPBoard account.') + return redirect("auth_services") @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def activate_jabber(request): logger.debug("activate_jabber called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] character = EveManager.get_character_by_id(authinfo.main_char_id) logger.debug("Adding jabber user for user %s with main character %s" % (request.user, character)) info = OpenfireManager.add_user(character.character_name) # If our username is blank means we already had a user if info[0] is not "": - AuthServicesInfoManager.update_user_jabber_info(info[0], info[1], request.user) + AuthServicesInfoManager.update_user_jabber_info(info[0], request.user) logger.debug("Updated authserviceinfo for user %s with jabber credentials. Updating groups." % request.user) update_jabber_groups.delay(request.user.pk) - logger.info("Succesfully activated jabber for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccesful attempt to activate jabber for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + logger.info("Successfully activated jabber for user %s" % request.user) + messages.success(request, 'Activated jabber account.') + credentials = { + 'username': info[0], + 'password': info[1], + } + return render(request, 'registered/service_credentials.html', + context={'credentials': credentials, 'service': 'Jabber'}) + else: + logger.error("UnSuccessful attempt to activate jabber for user %s" % request.user) + messages.error(request, 'An error occurred while processing your jabber account.') + return redirect("auth_services") @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def deactivate_jabber(request): logger.debug("deactivate_jabber called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = OpenfireManager.delete_user(authinfo.jabber_username) # If our username is blank means we failed if result: - AuthServicesInfoManager.update_user_jabber_info("", "", request.user) - logger.info("Succesfully deactivated jabber for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccesful attempt to deactivate jabber for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + AuthServicesInfoManager.update_user_jabber_info("", request.user) + logger.info("Successfully deactivated jabber for user %s" % request.user) + messages.success(request, 'Deactivated jabber account.') + else: + logger.error("UnSuccessful attempt to deactivate jabber for user %s" % request.user) + messages.error(request, 'An error occurred while processing your jabber account.') + return redirect("auth_services") @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def reset_jabber_password(request): logger.debug("reset_jabber_password called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = OpenfireManager.update_user_pass(authinfo.jabber_username) # If our username is blank means we failed if result != "": - AuthServicesInfoManager.update_user_jabber_info(authinfo.jabber_username, result, request.user) - logger.info("Succesfully reset jabber password for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccessful attempt to reset jabber for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + AuthServicesInfoManager.update_user_jabber_info(authinfo.jabber_username, request.user) + logger.info("Successfully reset jabber password for user %s" % request.user) + messages.success(request, 'Reset jabber password.') + credentials = { + 'username': authinfo.jabber_username, + 'password': result, + } + return render(request, 'registered/service_credentials.html', + context={'credentials': credentials, 'service': 'Jabber'}) + else: + logger.error("Unsuccessful attempt to reset jabber for user %s" % request.user) + messages.error(request, 'An error occurred while processing your jabber account.') + return redirect("auth_services") @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def activate_mumble(request): logger.debug("activate_mumble called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] character = EveManager.get_character_by_id(authinfo.main_char_id) ticker = character.corporation_ticker - if check_if_user_has_permission(request.user, "blue_member"): + if authinfo.state == BLUE_STATE: logger.debug("Adding mumble user for blue user %s with main character %s" % (request.user, character)) # Blue members should have alliance ticker (if in alliance) if EveAllianceInfo.objects.filter(alliance_id=character.alliance_id).exists(): @@ -375,55 +471,72 @@ def activate_mumble(request): result = MumbleManager.create_user(ticker, character.character_name) # if its empty we failed if result[0] is not "": - AuthServicesInfoManager.update_user_mumble_info(result[0], result[1], request.user) + AuthServicesInfoManager.update_user_mumble_info(result[0], request.user) logger.debug("Updated authserviceinfo for user %s with mumble credentials. Updating groups." % request.user) update_mumble_groups.delay(request.user.pk) - logger.info("Succesfully activated mumble for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccessful attempt to activate mumble for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + logger.info("Successfully activated mumble for user %s" % request.user) + messages.success(request, 'Activated Mumble account.') + credentials = { + 'username': result[0], + 'password': result[1], + } + return render(request, 'registered/service_credentials.html', + context={'credentials': credentials, 'service': 'Mumble'}) + else: + logger.error("Unsuccessful attempt to activate mumble for user %s" % request.user) + messages.error(request, 'An error occurred while processing your Mumble account.') + return redirect("auth_services") @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def deactivate_mumble(request): logger.debug("deactivate_mumble called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = MumbleManager.delete_user(authinfo.mumble_username) # if false we failed if result: - AuthServicesInfoManager.update_user_mumble_info("", "", request.user) - logger.info("Succesfully deactivated mumble for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccessful attempt to deactivate mumble for user %s" % request.user) - return HttpResponseRedirect("/") + AuthServicesInfoManager.update_user_mumble_info("", request.user) + logger.info("Successfully deactivated mumble for user %s" % request.user) + messages.success(request, 'Deactivated Mumble account.') + else: + logger.error("Unsuccessful attempt to deactivate mumble for user %s" % request.user) + messages.error(request, 'An error occurred while processing your Mumble account.') + return redirect("auth_services") @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def reset_mumble_password(request): logger.debug("reset_mumble_password called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = MumbleManager.update_user_password(authinfo.mumble_username) # if blank we failed if result != "": - AuthServicesInfoManager.update_user_mumble_info(authinfo.mumble_username, result, request.user) - logger.info("Succesfully reset mumble password for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccesful attempt to reset mumble password for user %s" % request.user) - return HttpResponseRedirect("/") + logger.info("Successfully reset mumble password for user %s" % request.user) + messages.success(request, 'Reset Mumble password.') + credentials = { + 'username': authinfo.mumble_username, + 'password': result, + } + return render(request, 'registered/service_credentials.html', + context={'credentials': credentials, 'service': 'Mumble'}) + else: + logger.error("UnSuccessful attempt to reset mumble password for user %s" % request.user) + messages.error(request, 'An error occurred while processing your Mumble account.') + return redirect("auth_services") @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def activate_teamspeak3(request): logger.debug("activate_teamspeak3 called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] character = EveManager.get_character_by_id(authinfo.main_char_id) ticker = character.corporation_ticker - if check_if_user_has_permission(request.user, "blue_member"): + if authinfo.state == BLUE_STATE: logger.debug("Adding TS3 user for blue user %s with main character %s" % (request.user, character)) # Blue members should have alliance ticker (if in alliance) if EveAllianceInfo.objects.filter(alliance_id=character.alliance_id).exists(): @@ -438,60 +551,67 @@ def activate_teamspeak3(request): if result[0] is not "": AuthServicesInfoManager.update_user_teamspeak3_info(result[0], result[1], request.user) logger.debug("Updated authserviceinfo for user %s with TS3 credentials. Updating groups." % request.user) - logger.info("Succesfully activated TS3 for user %s" % request.user) - return HttpResponseRedirect("/verify_teamspeak3/") + logger.info("Successfully activated TS3 for user %s" % request.user) + messages.success(request, 'Activated TeamSpeak3 account.') + return redirect("auth_verify_teamspeak3") logger.error("Unsuccessful attempt to activate TS3 for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + messages.error(request, 'An error occurred while processing your TeamSpeak3 account.') + return redirect("auth_services") + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def verify_teamspeak3(request): logger.debug("verify_teamspeak3 called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] if not authinfo.teamspeak3_uid: logger.warn("Unable to validate user %s teamspeak: no teamspeak data" % request.user) - return HttpResponseRedirect("/services") + return redirect("auth_services") if request.method == "POST": form = TeamspeakJoinForm(request.POST) if form.is_valid(): update_teamspeak3_groups.delay(request.user.pk) logger.debug("Validated user %s joined TS server" % request.user) - return HttpResponseRedirect("/services/") + return redirect("auth_services") else: - form = TeamspeakJoinForm({'username':authinfo.teamspeak3_uid}) + form = TeamspeakJoinForm({'username': authinfo.teamspeak3_uid}) context = { 'form': form, 'authinfo': authinfo, } - return render_to_response('registered/teamspeakjoin.html', context, context_instance=RequestContext(request)) + return render(request, 'registered/teamspeakjoin.html', context=context) + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def deactivate_teamspeak3(request): logger.debug("deactivate_teamspeak3 called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = Teamspeak3Manager.delete_user(authinfo.teamspeak3_uid) # if false we failed if result: AuthServicesInfoManager.update_user_teamspeak3_info("", "", request.user) - logger.info("Succesfully deactivated TS3 for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccessful attempt to deactivate TS3 for user %s" % request.user) - return HttpResponseRedirect("/") + logger.info("Successfully deactivated TS3 for user %s" % request.user) + messages.success(request, 'Deactivated TeamSpeak3 account.') + else: + logger.error("Unsuccessful attempt to deactivate TS3 for user %s" % request.user) + messages.error(request, 'An error occurred while processing your TeamSpeak3 account.') + return redirect("auth_services") @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def reset_teamspeak3_perm(request): logger.debug("reset_teamspeak3_perm called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] character = EveManager.get_character_by_id(authinfo.main_char_id) logger.debug("Deleting TS3 user for user %s" % request.user) Teamspeak3Manager.delete_user(authinfo.teamspeak3_uid) - if check_if_user_has_permission(request.user, "blue_member"): - logger.debug("Generating new permission key for blue user %s with main character %s" % (request.user, character)) + if authinfo.state == BLUE_STATE: + logger.debug( + "Generating new permission key for blue user %s with main character %s" % (request.user, character)) result = Teamspeak3Manager.generate_new_blue_permissionkey(authinfo.teamspeak3_uid, character.character_name, character.corporation_ticker) else: @@ -505,78 +625,83 @@ def reset_teamspeak3_perm(request): logger.debug("Updated authserviceinfo for user %s with TS3 credentials. Updating groups." % request.user) update_teamspeak3_groups.delay(request.user) logger.info("Successfully reset TS3 permission key for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccessful attempt to reset TS3 permission key for user %s" % request.user) - return HttpResponseRedirect("/") + messages.success(request, 'Reset TeamSpeak3 permission key.') + else: + logger.error("Unsuccessful attempt to reset TS3 permission key for user %s" % request.user) + messages.error(request, 'An error occurred while processing your TeamSpeak3 account.') + return redirect("auth_services") + @login_required -def fleet_fits(request): - logger.debug("fleet_fits called by user %s" % request.user) - context = {} - return render_to_response('registered/fleetfits.html', context, -context_instance=RequestContext(request)) - -@login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def deactivate_discord(request): logger.debug("deactivate_discord called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = DiscordOAuthManager.delete_user(authinfo.discord_uid) if result: AuthServicesInfoManager.update_user_discord_info("", request.user) - logger.info("Succesfully deactivated discord for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccesful attempt to deactivate discord for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + logger.info("Successfully deactivated discord for user %s" % request.user) + messages.success(request, 'Deactivated Discord account.') + else: + logger.error("UnSuccessful attempt to deactivate discord for user %s" % request.user) + messages.error(request, 'An error occurred while processing your Discord account.') + return redirect("auth_services") + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def reset_discord(request): logger.debug("reset_discord called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = DiscordOAuthManager.delete_user(authinfo.discord_uid) if result: - AuthServicesInfoManager.update_user_discord_info("",request.user) - logger.info("Succesfully deleted discord user for user %s - forwarding to discord activation." % request.user) - return HttpResponseRedirect("/activate_discord/") + AuthServicesInfoManager.update_user_discord_info("", request.user) + logger.info("Successfully deleted discord user for user %s - forwarding to discord activation." % request.user) + return redirect("auth_activate_discord") logger.error("Unsuccessful attempt to reset discord for user %s" % request.user) - return HttpResponseRedirect("/services/") + messages.error(request, 'An error occurred while processing your Discord account.') + return redirect("auth_services") + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def activate_discord(request): logger.debug("activate_discord called by user %s" % request.user) - return HttpResponseRedirect(DiscordOAuthManager.generate_oauth_redirect_url()) + return redirect(DiscordOAuthManager.generate_oauth_redirect_url()) + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def discord_callback(request): logger.debug("Received Discord callback for activation of user %s" % request.user) code = request.GET.get('code', None) if not code: logger.warn("Did not receive OAuth code from callback of user %s" % request.user) - return HttpResponseRedirect("/services/") + return redirect("auth_services") user_id = DiscordOAuthManager.add_user(code) if user_id: AuthServicesInfoManager.update_user_discord_info(user_id, request.user) - if (settings.DISCORD_SYNC_NAMES): + if settings.DISCORD_SYNC_NAMES: update_discord_nickname.delay(request.user.pk) update_discord_groups.delay(request.user.pk) - logger.info("Succesfully activated Discord for user %s" % request.user) + logger.info("Successfully activated Discord for user %s" % request.user) + messages.success(request, 'Activated Discord account.') else: logger.error("Failed to activate Discord for user %s" % request.user) - return HttpResponseRedirect("/services/") + messages.error(request, 'An error occurred while processing your Discord account.') + return redirect("auth_services") + @login_required @user_passes_test(superuser_test) def discord_add_bot(request): - return HttpResponseRedirect(DiscordOAuthManager.generate_bot_add_url()) + return redirect(DiscordOAuthManager.generate_bot_add_url()) + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def set_forum_password(request): logger.debug("set_forum_password called by user %s" % request.user) - error = None if request.method == 'POST': logger.debug("Received POST request with form.") form = ServicePasswordForm(request.POST) @@ -584,30 +709,29 @@ def set_forum_password(request): if form.is_valid(): password = form.cleaned_data['password'] logger.debug("Form contains password of length %s" % len(password)) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) - result = Phpbb3Manager.update_user_password(authinfo.forum_username, authinfo.main_char_id, password=password) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] + result = Phpbb3Manager.update_user_password(authinfo.forum_username, authinfo.main_char_id, + password=password) if result != "": - AuthServicesInfoManager.update_user_forum_info(authinfo.forum_username, result, request.user) - logger.info("Succesfully reset forum password for user %s" % request.user) - return HttpResponseRedirect("/services/") + logger.info("Successfully set forum password for user %s" % request.user) + messages.success('Set forum password.') else: logger.error("Failed to install custom forum password for user %s" % request.user) - error = "Failed to install custom password." - else: - error = "Invalid password provided" + messages.error(request, 'An error occurred while processing your forum account.') + return redirect("auth_services") else: logger.debug("Request is not type POST - providing empty form.") form = ServicePasswordForm() logger.debug("Rendering form for user %s" % request.user) context = {'form': form, 'service': 'Forum'} - return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) + return render(request, 'registered/service_password.html', context=context) + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def set_mumble_password(request): logger.debug("set_mumble_password called by user %s" % request.user) - error = None if request.method == 'POST': logger.debug("Received POST request with form.") form = ServicePasswordForm(request.POST) @@ -615,30 +739,28 @@ def set_mumble_password(request): if form.is_valid(): password = form.cleaned_data['password'] logger.debug("Form contains password of length %s" % len(password)) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = MumbleManager.update_user_password(authinfo.mumble_username, password=password) if result != "": - AuthServicesInfoManager.update_user_mumble_info(authinfo.mumble_username, result, request.user) - logger.info("Succesfully reset forum password for user %s" % request.user) - return HttpResponseRedirect("/services/") + logger.info("Successfully reset forum password for user %s" % request.user) + messages.success(request, 'Set Mumble password.') else: logger.error("Failed to install custom mumble password for user %s" % request.user) - error = "Failed to install custom password." - else: - error = "Invalid password provided" + messages.error(request, 'An error occurred while processing your Mumble account.') + return redirect("auth_services") else: logger.debug("Request is not type POST - providing empty form.") form = ServicePasswordForm() logger.debug("Rendering form for user %s" % request.user) - context = {'form': form, 'service': 'Mumble', 'error': error} - return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) + context = {'form': form, 'service': 'Mumble'} + return render(request, 'registered/service_password.html', context=context) + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def set_jabber_password(request): logger.debug("set_jabber_password called by user %s" % request.user) - error = None if request.method == 'POST': logger.debug("Received POST request with form.") form = ServicePasswordForm(request.POST) @@ -646,27 +768,26 @@ def set_jabber_password(request): if form.is_valid(): password = form.cleaned_data['password'] logger.debug("Form contains password of length %s" % len(password)) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = OpenfireManager.update_user_pass(authinfo.jabber_username, password=password) if result != "": - AuthServicesInfoManager.update_user_jabber_info(authinfo.jabber_username, result, request.user) - logger.info("Succesfully reset forum password for user %s" % request.user) - return HttpResponseRedirect("/services/") + logger.info("Successfully set jabber password for user %s" % request.user) + messages.success(request, 'Set jabber password.') else: logger.error("Failed to install custom jabber password for user %s" % request.user) - error = "Failed to install custom password." - else: - error = "Invalid password provided" + messages.error(request, 'An error occurred while processing your jabber account.') + return redirect("auth_services") else: logger.debug("Request is not type POST - providing empty form.") form = ServicePasswordForm() logger.debug("Rendering form for user %s" % request.user) - context = {'form': form, 'service': 'Jabber', 'error': error} - return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) + context = {'form': form, 'service': 'Jabber'} + return render(request, 'registered/service_password.html', context=context) + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def set_ipboard_password(request): logger.debug("set_ipboard_password called by user %s" % request.user) error = None @@ -677,95 +798,122 @@ def set_ipboard_password(request): if form.is_valid(): password = form.cleaned_data['password'] logger.debug("Form contains password of length %s" % len(password)) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) - result = IPBoardManager.update_user_password(authinfo.ipboard_username, request.user.email, plain_password=password) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] + result = IPBoardManager.update_user_password(authinfo.ipboard_username, request.user.email, + plain_password=password) if result != "": - AuthServicesInfoManager.update_user_ipboard_info(authinfo.ipboard_username, result, request.user) - logger.info("Succesfully reset forum password for user %s" % request.user) - return HttpResponseRedirect("/services/") + logger.info("Successfully set IPBoard password for user %s" % request.user) + messages.success(request, 'Set IPBoard password.') else: logger.error("Failed to install custom ipboard password for user %s" % request.user) - error = "Failed to install custom password." - else: - error = "Invalid password provided" + messages.error(request, 'An error occurred while processing your IPBoard account.') + return redirect("auth_services") else: logger.debug("Request is not type POST - providing empty form.") form = ServicePasswordForm() logger.debug("Rendering form for user %s" % request.user) context = {'form': form, 'service': 'IPBoard', 'error': error} - return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) - + return render(request, 'registered/service_password.html', context=context) + + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def activate_discourse(request): logger.debug("activate_discourse called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] character = EveManager.get_character_by_id(authinfo.main_char_id) logger.debug("Adding discourse user for user %s with main character %s" % (request.user, character)) result = DiscourseManager.add_user(character.character_name, request.user.email) if result[0] != "": - AuthServicesInfoManager.update_user_discourse_info(result[0], result[1], request.user) + AuthServicesInfoManager.update_user_discourse_info(result[0], request.user) logger.debug("Updated authserviceinfo for user %s with discourse credentials. Updating groups." % request.user) update_discourse_groups.delay(request.user.pk) logger.info("Successfully activated discourse for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccessful attempt to activate forum for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + messages.success('Activated Discourse account.') + messages.warning('Do not lose your Discourse password. It cannot be reset through auth.') + credentials = { + 'username': result[0], + 'password': result[1], + } + return render(request, 'registered/service_credentials.html', + context={'credentials': credentials, 'service': 'Discourse'}) + else: + logger.error("Unsuccessful attempt to activate forum for user %s" % request.user) + messages.error(request, 'An error occurred while processing your Discourse account.') + return redirect("auth_services") @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def deactivate_discourse(request): logger.debug("deactivate_discourse called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = DiscourseManager.delete_user(authinfo.discourse_username) if result: - AuthServicesInfoManager.update_user_discourse_info("", "", request.user) + AuthServicesInfoManager.update_user_discourse_info("", request.user) logger.info("Successfully deactivated discourse for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccessful attempt to activate discourse for user %s" % request.user) - return HttpResponseRedirect("/dashboard") - + messages.success('Deactivated Discourse account.') + else: + logger.error("Unsuccessful attempt to activate discourse for user %s" % request.user) + messages.error(request, 'An error occurred while processing your Discourse account.') + return redirect("auth_services") + + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def activate_ips4(request): logger.debug("activate_ips4 called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] # Valid now we get the main characters character = EveManager.get_character_by_id(authinfo.main_char_id) logger.debug("Adding IPS4 user for user %s with main character %s" % (request.user, character)) result = Ips4Manager.add_user(character.character_name, request.user.email) # if empty we failed if result[0] != "": - AuthServicesInfoManager.update_user_ips4_info(result[0], result[1], result[2], request.user) + AuthServicesInfoManager.update_user_ips4_info(result[0], result[2], request.user) logger.debug("Updated authserviceinfo for user %s with IPS4 credentials." % request.user) - #update_ips4_groups.delay(request.user.pk) - logger.info("Succesfully activated IPS4 for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccesful attempt to activate IPS4 for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + # update_ips4_groups.delay(request.user.pk) + logger.info("Successfully activated IPS4 for user %s" % request.user) + messages.success(request, 'Activated IPSuite4 account.') + credentials = { + 'username': result[0], + 'password': result[1], + } + return render(request, 'registered/service_credentials.html', + context={'credentials': credentials, 'service': 'IPSuite4'}) + else: + logger.error("UnSuccessful attempt to activate IPS4 for user %s" % request.user) + messages.error(request, 'An error occurred while processing your IPSuite4 account.') + return redirect("auth_services") + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def reset_ips4_password(request): logger.debug("reset_ips4_password called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = Ips4Manager.update_user_password(authinfo.ips4_username) - member_id = Ips4Manager.get_user_id(authinfo.ips4_username) # false we failed if result != "": - AuthServicesInfoManager.update_user_ips4_info(authinfo.ips4_username, result, member_id, request.user) - logger.info("Succesfully reset IPS4 password for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccessful attempt to reset IPS4 password for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + logger.info("Successfully reset IPS4 password for user %s" % request.user) + messages.success(request, 'Reset IPSuite4 password.') + credentials = { + 'username': authinfo.ips4_username, + 'password': result, + } + return render(request, 'registered/service_credentials.html', + context={'credentials': credentials, 'service': 'IPSuite4'}) + else: + logger.error("Unsuccessful attempt to reset IPS4 password for user %s" % request.user) + messages.error(request, 'An error occurred while processing your IPSuite4 account.') + return redirect("auth_services") + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def set_ips4_password(request): logger.debug("set_ips4_password called by user %s" % request.user) - error = None if request.method == 'POST': logger.debug("Received POST request with form.") form = ServicePasswordForm(request.POST) @@ -773,93 +921,111 @@ def set_ips4_password(request): if form.is_valid(): password = form.cleaned_data['password'] logger.debug("Form contains password of length %s" % len(password)) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = Ips4Manager.update_custom_password(authinfo.ips4_username, plain_password=password) - member_id = Ips4Manager.get_user_id(authinfo.ips4_username) if result != "": - AuthServicesInfoManager.update_user_ips4_info(authinfo.ips4_username, result, member_id, request.user) - logger.info("Succesfully reset IPS4 password for user %s" % request.user) - return HttpResponseRedirect("/services/") + logger.info("Successfully set IPS4 password for user %s" % request.user) + messages.success(request, 'Set IPSuite4 password.') else: logger.error("Failed to install custom IPS4 password for user %s" % request.user) - error = "Failed to install custom password." - else: - error = "Invalid password provided" + messages.error(request, 'An error occurred while processing your IPSuite4 account.') + return redirect('auth_services') else: logger.debug("Request is not type POST - providing empty form.") form = ServicePasswordForm() logger.debug("Rendering form for user %s" % request.user) - context = {'form': form, 'service': 'IPS4', 'error': error} - return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) + context = {'form': form, 'service': 'IPS4'} + return render(request, 'registered/service_password.html', context=context) + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def deactivate_ips4(request): logger.debug("deactivate_ips4 called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = Ips4Manager.delete_user(authinfo.ips4_id) if result != "": - AuthServicesInfoManager.update_user_ips4_info("", "", "", request.user) - logger.info("Succesfully deactivated IPS4 for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccesful attempt to deactivate IPS4 for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + AuthServicesInfoManager.update_user_ips4_info("", "", request.user) + logger.info("Successfully deactivated IPS4 for user %s" % request.user) + messages.success(request, 'Deactivated IPSuite4 account.') + else: + logger.error("UnSuccessful attempt to deactivate IPS4 for user %s" % request.user) + messages.error(request, 'An error occurred while processing your IPSuite4 account.') + return redirect("auth_services") + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def activate_smf(request): logger.debug("activate_smf called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] # Valid now we get the main characters character = EveManager.get_character_by_id(authinfo.main_char_id) logger.debug("Adding smf user for user %s with main character %s" % (request.user, character)) result = smfManager.add_user(character.character_name, request.user.email, ['Member'], authinfo.main_char_id) # if empty we failed if result[0] != "": - AuthServicesInfoManager.update_user_smf_info(result[0], result[1], request.user) + AuthServicesInfoManager.update_user_smf_info(result[0], request.user) logger.debug("Updated authserviceinfo for user %s with smf credentials. Updating groups." % request.user) update_smf_groups.delay(request.user.pk) - logger.info("Succesfully activated smf for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccesful attempt to activate smf for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + logger.info("Successfully activated smf for user %s" % request.user) + messages.success(request, 'Activated SMF account.') + credentials = { + 'username': result[0], + 'password': result[1], + } + return render(request, 'registered/service_credentials.html', + context={'credentials': credentials, 'service': 'SMF'}) + else: + logger.error("UnSuccessful attempt to activate smf for user %s" % request.user) + messages.error(request, 'An error occurred while processing your SMF account.') + return redirect("auth_services") @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def deactivate_smf(request): logger.debug("deactivate_smf called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = smfManager.disable_user(authinfo.smf_username) # false we failed if result: - AuthServicesInfoManager.update_user_smf_info("", "", request.user) - logger.info("Succesfully deactivated smf for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccesful attempt to activate smf for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + AuthServicesInfoManager.update_user_smf_info("", request.user) + logger.info("Successfully deactivated smf for user %s" % request.user) + messages.success(request, 'Deactivated SMF account.') + else: + logger.error("UnSuccessful attempt to activate smf for user %s" % request.user) + messages.error(request, 'An error occurred while processing your SMF account.') + return redirect("auth_services") @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def reset_smf_password(request): logger.debug("reset_smf_password called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = smfManager.update_user_password(authinfo.smf_username, authinfo.main_char_id) # false we failed if result != "": - AuthServicesInfoManager.update_user_smf_info(authinfo.smf_username, result, request.user) - logger.info("Succesfully reset smf password for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccessful attempt to reset smf password for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + logger.info("Successfully reset smf password for user %s" % request.user) + messages.success(request, 'Reset SMF password.') + credentials = { + 'username': authinfo.smf_username, + 'password': result, + } + return render(request, 'registered/service_credentials.html', + context={'credentials': credentials, 'service': 'SMF'}) + else: + logger.error("Unsuccessful attempt to reset smf password for user %s" % request.user) + messages.error(request, 'An error occurred while processing your SMF account.') + return redirect("auth_services") + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def set_smf_password(request): logger.debug("set_smf_password called by user %s" % request.user) - error = None if request.method == 'POST': logger.debug("Received POST request with form.") form = ServicePasswordForm(request.POST) @@ -867,78 +1033,95 @@ def set_smf_password(request): if form.is_valid(): password = form.cleaned_data['password'] logger.debug("Form contains password of length %s" % len(password)) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = smfManager.update_user_password(authinfo.smf_username, authinfo.main_char_id, password=password) if result != "": - AuthServicesInfoManager.update_user_smf_info(authinfo.smf_username, result, request.user) - logger.info("Succesfully reset smf password for user %s" % request.user) - return HttpResponseRedirect("/services/") + logger.info("Successfully set smf password for user %s" % request.user) + messages.success(request, 'Set SMF password.') else: logger.error("Failed to install custom smf password for user %s" % request.user) - error = "Failed to install custom password." - else: - error = "Invalid password provided" + messages.error(request, 'An error occurred while processing your SMF account.') + return redirect("auth_services") else: logger.debug("Request is not type POST - providing empty form.") form = ServicePasswordForm() logger.debug("Rendering form for user %s" % request.user) context = {'form': form, 'service': 'SMF'} - return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) + return render(request, 'registered/service_password.html', context=context) + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def activate_market(request): logger.debug("activate_market called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] # Valid now we get the main characters character = EveManager.get_character_by_id(authinfo.main_char_id) logger.debug("Adding market user for user %s with main character %s" % (request.user, character)) - result = marketManager.add_user(character.character_name, request.user.email, authinfo.main_char_id, character.character_name) + result = marketManager.add_user(character.character_name, request.user.email, authinfo.main_char_id, + character.character_name) # if empty we failed if result[0] != "": - AuthServicesInfoManager.update_user_market_info(result[0], result[1], request.user) + AuthServicesInfoManager.update_user_market_info(result[0], request.user) logger.debug("Updated authserviceinfo for user %s with market credentials." % request.user) - logger.info("Succesfully activated market for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccesful attempt to activate market for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + logger.info("Successfully activated market for user %s" % request.user) + messages.success(request, 'Activated Alliance Market account.') + credentials = { + 'username': result[0], + 'password': result[1], + } + return render(request, 'registered/service_credentials.html', + context={'credentials': credentials, 'service': 'Alliance Market'}) + else: + logger.error("UnSuccessful attempt to activate market for user %s" % request.user) + messages.error(request, 'An error occurred while processing your Alliance Market account.') + return redirect("auth_services") @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def deactivate_market(request): logger.debug("deactivate_market called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = marketManager.disable_user(authinfo.market_username) # false we failed if result: - AuthServicesInfoManager.update_user_market_info("", "", request.user) - logger.info("Succesfully deactivated market for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccesful attempt to activate market for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + AuthServicesInfoManager.update_user_market_info("", request.user) + logger.info("Successfully deactivated market for user %s" % request.user) + messages.success(request, 'Deactivated Alliance Market account.') + else: + logger.error("UnSuccessful attempt to activate market for user %s" % request.user) + messages.error(request, 'An error occurred while processing your Alliance Market account.') + return redirect("auth_services") @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def reset_market_password(request): logger.debug("reset_market_password called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = marketManager.update_user_password(authinfo.market_username) # false we failed if result != "": - AuthServicesInfoManager.update_user_market_info(authinfo.market_username, result, request.user) - logger.info("Succesfully reset market password for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccessful attempt to reset market password for user %s" % request.user) - return HttpResponseRedirect("/dashboard") + logger.info("Successfully reset market password for user %s" % request.user) + messages.success(request, 'Reset Alliance Market password.') + credentials = { + 'username': authinfo.market_username, + 'password': result, + } + return render(request, 'registered/service_credentials.html', + context={'credentials': credentials, 'service': 'Alliance Market'}) + else: + logger.error("Unsuccessful attempt to reset market password for user %s" % request.user) + messages.error(request, 'An error occurred while processing your Alliance Market account.') + return redirect("auth_services") + @login_required -@user_passes_test(service_blue_alliance_test) +@members_and_blues() def set_market_password(request): logger.debug("set_market_password called by user %s" % request.user) - error = None if request.method == 'POST': logger.debug("Received POST request with form.") form = ServicePasswordForm(request.POST) @@ -946,100 +1129,19 @@ def set_market_password(request): if form.is_valid(): password = form.cleaned_data['password'] logger.debug("Form contains password of length %s" % len(password)) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] result = marketManager.update_custom_password(authinfo.market_username, password) if result != "": - AuthServicesInfoManager.update_user_market_info(authinfo.market_username, result, request.user) - logger.info("Succesfully reset market password for user %s" % request.user) - return HttpResponseRedirect("/services/") + logger.info("Successfully reset market password for user %s" % request.user) + messages.success(request, 'Set Alliance Market password.') else: logger.error("Failed to install custom market password for user %s" % request.user) - error = "Failed to install custom password." - else: - error = "Invalid password provided" + messages.error(request, 'An error occurred while processing your Alliance Market account.') + return redirect("auth_services") else: logger.debug("Request is not type POST - providing empty form.") form = ServicePasswordForm() logger.debug("Rendering form for user %s" % request.user) context = {'form': form, 'service': 'Market'} - return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) - -@login_required -@user_passes_test(service_blue_alliance_test) -def activate_pathfinder(request): - logger.debug("activate_pathfinder called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) - # Valid now we get the main characters - character = EveManager.get_character_by_id(authinfo.main_char_id) - logger.debug("Adding pathfinder for user %s with main character %s" % (request.user, character)) - result = pathfinderManager.add_user(character.character_name, request.user.email, character.character_name) - # if empty we failed - if result[0] != "": - AuthServicesInfoManager.update_user_pathfinder_info(result[0], result[1], request.user) - logger.debug("Updated authserviceinfo for user %s with pathfinder credentials." % request.user) - logger.info("Succesfully activated pathfinder for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccesful attempt to activate pathfinder for user %s" % request.user) - return HttpResponseRedirect("/dashboard") - - -@login_required -@user_passes_test(service_blue_alliance_test) -def deactivate_pathfinder(request): - logger.debug("deactivate_pathfinder called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) - result = pathfinderManager.disable_user(authinfo.pathfinder_username) - # false we failed - if result: - AuthServicesInfoManager.update_user_pathfinder_info("", "", request.user) - logger.info("Succesfully deactivated pathfinder for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccesful attempt to activate pathfinder for user %s" % request.user) - return HttpResponseRedirect("/dashboard") - - -@login_required -@user_passes_test(service_blue_alliance_test) -def reset_pathfinder_password(request): - logger.debug("reset_pathfinder_password called by user %s" % request.user) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) - result = pathfinderManager.update_user_info(authinfo.pathfinder_username) - # false we failed - if result != "": - AuthServicesInfoManager.update_user_pathfinder_info(authinfo.pathfinder_username, result[1], request.user) - logger.info("Succesfully reset pathfinder password for user %s" % request.user) - return HttpResponseRedirect("/services/") - logger.error("Unsuccessful attempt to reset pathfinder password for user %s" % request.user) - return HttpResponseRedirect("/dashboard") - -@login_required -@user_passes_test(service_blue_alliance_test) -def set_pathfinder_password(request): - logger.debug("set_pathfinder_password called by user %s" % request.user) - error = None - if request.method == 'POST': - logger.debug("Received POST request with form.") - form = ServicePasswordForm(request.POST) - logger.debug("Form is valid: %s" % form.is_valid()) - if form.is_valid(): - password = form.cleaned_data['password'] - logger.debug("Form contains password of length %s" % len(password)) - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) - result = pathfinderManager.update_custom_password(authinfo.pathfinder_username, password) - if result != "": - AuthServicesInfoManager.update_user_pathfinder_info(authinfo.pathfinder_username, result, request.user) - logger.info("Succesfully reset pathfinder password for user %s" % request.user) - return HttpResponseRedirect("/services/") - else: - logger.error("Failed to install custom pathfinder password for user %s" % request.user) - error = "Failed to install custom password." - else: - error = "Invalid password provided" - else: - logger.debug("Request is not type POST - providing empty form.") - form = ServicePasswordForm() - - logger.debug("Rendering form for user %s" % request.user) - context = {'form': form, 'service': 'Pathfinder'} - return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) + return render(request, 'registered/service_password.html', context=context) diff --git a/sigtracker/admin.py b/sigtracker/admin.py deleted file mode 100644 index 00541e4f..00000000 --- a/sigtracker/admin.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.contrib import admin - -from models import sigtracker - -admin.site.register(sigtracker) -# Register your models here. diff --git a/sigtracker/form.py b/sigtracker/form.py deleted file mode 100644 index 7817a581..00000000 --- a/sigtracker/form.py +++ /dev/null @@ -1,26 +0,0 @@ -from django import forms -from django.core.validators import MaxValueValidator, MinValueValidator -from django.utils.translation import ugettext_lazy as _ - - -class SignatureForm(forms.Form): - mass_status = [(_('More Than 50%'), _('More Than 50%')), (_('Less Than 50%'), _('Less Than 50%')), (_('Less Than 10%'), _('Less Than 10%'))] - lifetime_status = [(_('More Than 24 Hours'), _('More Than 24 Hours')), (_('Less Than 24 Hours'), _('Less Than 24 Hours')), (_('Less Than 4 Hours'), _('Less Than 4 Hours'))] - ships_size = [(_('Only Smallest'), _('Only Smallest')), (_('Up to Medium'), _('Up to Medium')), (_('Larger'), _('Larger')), (_('Very Large'), _('Very Large'))] - - - system = forms.CharField(max_length=254, required=True, label=_('System')) - ident = forms.CharField(max_length=254, required=True, label=_("ID")) - lifetime_status = forms.ChoiceField(choices=lifetime_status, required=True, label=_("Lifetime Status")) - mass_status = forms.ChoiceField(choices=mass_status, required=True, label=_("Mass Status")) - ships_size = forms.ChoiceField(choices=ships_size, required=True, label=_("Ship Size")) - destination = forms.CharField(max_length=254, label=_("End Destination"), required=True, initial="") - through_dest = forms.CharField(max_length=254, label=_("Goes Through"), required=True, initial="") - notes = forms.CharField(max_length=254, label=_("Notes"), required=False, initial="") - - - - - - - diff --git a/sigtracker/models.py b/sigtracker/models.py deleted file mode 100644 index 03c3c344..00000000 --- a/sigtracker/models.py +++ /dev/null @@ -1,22 +0,0 @@ -from django.db import models -from django.contrib.auth.models import User -from django.utils import timezone -from eveonline.models import EveCharacter -from eveonline.models import EveCorporationInfo - - -class sigtracker(models.Model): - class Meta: - ordering = ['post_time'] - ident = models.CharField(max_length=254, default="") - system = models.CharField(max_length=254, default="") - destination = models.CharField(max_length=254, default="") - lifetime_status = models.CharField(max_length=254, default="") - mass_status = models.CharField(max_length=254, default="") - ships_size = models.CharField(max_length=254, default="") - notes = models.CharField(max_length=254, default="") - through_dest = models.CharField(max_length=254, default="") - post_time = models.DateTimeField(default=timezone.now) - eve_character = models.ForeignKey(EveCharacter) - - diff --git a/sigtracker/tests.py b/sigtracker/tests.py deleted file mode 100644 index a39b155a..00000000 --- a/sigtracker/tests.py +++ /dev/null @@ -1 +0,0 @@ -# Create your tests here. diff --git a/sigtracker/views.py b/sigtracker/views.py deleted file mode 100644 index fbe12599..00000000 --- a/sigtracker/views.py +++ /dev/null @@ -1,122 +0,0 @@ -from django.http import HttpResponseRedirect -from django.template import RequestContext -from django.shortcuts import render_to_response -from django.contrib.auth.decorators import login_required -from django.contrib.auth.decorators import permission_required -from django.contrib.auth.decorators import user_passes_test -from django.shortcuts import get_object_or_404 -from django.utils import timezone - -from util import check_if_user_has_permission -from authentication.managers import AuthServicesInfoManager -from eveonline.managers import EveManager -from form import SignatureForm -from models import sigtracker - - -import logging - -logger = logging.getLogger(__name__) - -def sigtracker_util_test(user): - return check_if_user_has_permission(user, 'member') or check_if_user_has_permission(user, 'blue_member') - - -@login_required -@user_passes_test(sigtracker_util_test) -@permission_required('auth.signature_view') -def sigtracker_view(request): - logger.info("sigtracker_view called by user %s" % request.user) - sigtracker_list = sigtracker.objects.all() - render_items = {'sigtracker': sigtracker.objects.all(),} - - return render_to_response('registered/signaturemanagement.html', render_items, context_instance=RequestContext(request)) - - -@login_required -@permission_required('auth.signature_management') -def add_signature_view(request): - logger.info("add_signature_view called by user %s" % request.user) - if request.method == 'POST': - form = SignatureForm(request.POST) - logger.info("Request type POST contains form valid: %s" % form.is_valid()) - if form.is_valid(): - #Get Current Time - post_time = timezone.now() - # Get character - auth_info = AuthServicesInfoManager.get_auth_service_info(request.user) - character = EveManager.get_character_by_id(auth_info.main_char_id) - # handle valid form - sig = sigtracker() - sig.ident = form.cleaned_data['ident'] - sig.system = form.cleaned_data['system'] - sig.destination = form.cleaned_data['destination'] - sig.lifetime_status = form.cleaned_data['lifetime_status'] - sig.mass_status = form.cleaned_data['mass_status'] - sig.ships_size = form.cleaned_data['ships_size'] - sig.through_dest = form.cleaned_data['through_dest'] - sig.notes = form.cleaned_data['notes'] - sig.create_time = post_time - sig.eve_character = character - sig.save() - return HttpResponseRedirect("/sigtracker/") - else: - logger.info("Returning new SignatureForm") - form = SignatureForm() - - render_items = {'form': form} - - return render_to_response('registered/addsignature.html', render_items, context_instance=RequestContext(request)) - - -@login_required -@permission_required('auth.signature_management') -def remove_signature(request, sigtracker_id): - logger.info("remove_signature called by user %s for signature id %s" % (request.user, sigtracker_id)) - if sigtracker.objects.filter(id=sigtracker_id).exists(): - sig = sigtracker.objects.get(id=sigtracker_id) - sig.delete() - logger.info("Deleting sigtracker id %s by user %s" % (sigtracker_id, request.user)) - else: - logger.info("Unable to delete signature id %s for user %s - signature matching id not found." % (sigtracker_id, request.user)) - return HttpResponseRedirect("/sigtracker/") - - -@login_required -@permission_required('auth.signature_management') -def edit_signature(request, sigtracker_id): - logger.debug("edit_optimer called by user %s for optimer id %s" % (request.user, sigtracker_id)) - sig = get_object_or_404(sigtracker, id=sigtracker_id) - if request.method == 'POST': - form = SignatureForm(request.POST) - logger.debug("Received POST request containing update sigtracker form, is valid: %s" % form.is_valid()) - if form.is_valid(): - auth_info = AuthServicesInfoManager.get_auth_service_info(request.user) - character = EveManager.get_character_by_id(auth_info.main_char_id) - sig.ident = form.cleaned_data['ident'] - sig.system = form.cleaned_data['system'] - sig.destination = form.cleaned_data['destination'] - sig.lifetime_status = form.cleaned_data['lifetime_status'] - sig.mass_status = form.cleaned_data['mass_status'] - sig.ships_size = form.cleaned_data['ships_size'] - sig.through_dest = form.cleaned_data['through_dest'] - sig.notes = form.cleaned_data['notes'] - sig.eve_character = character - logger.info("User %s updating sigtracker id %s " % (request.user, sigtracker_id)) - sig.save() - - logger.debug("Detected no changes between sigtracker id %s and supplied form." % sigtracker_id) - return HttpResponseRedirect("/sigtracker/") - else: - data = { - 'ident': sig.ident, - 'system': sig.system, - 'destination': sig.destination, - 'lifetime_status': sig.lifetime_status, - 'mass_status': sig.mass_status, - 'ships_size': sig.ships_size, - 'through_dest': sig.through_dest, - 'notes': sig.notes, - } - form = SignatureForm(initial= data) - return render_to_response('registered/signatureupdate.html', {'form':form}, context_instance=RequestContext(request)) diff --git a/srp/__init__.py b/srp/__init__.py index e69de29b..baffc488 100755 --- a/srp/__init__.py +++ b/srp/__init__.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/srp/admin.py b/srp/admin.py index 5ddca89d..53eff30a 100755 --- a/srp/admin.py +++ b/srp/admin.py @@ -1,8 +1,8 @@ +from __future__ import unicode_literals from django.contrib import admin -from models import SrpFleetMain -from models import SrpUserRequest +from srp.models import SrpFleetMain +from srp.models import SrpUserRequest -# Register your models here. admin.site.register(SrpFleetMain) -admin.site.register(SrpUserRequest) \ No newline at end of file +admin.site.register(SrpUserRequest) diff --git a/srp/apps.py b/srp/apps.py new file mode 100644 index 00000000..93027128 --- /dev/null +++ b/srp/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class SRPConfig(AppConfig): + name = 'srp' diff --git a/srp/form.py b/srp/form.py index 4cc64ac3..7dfccfe6 100755 --- a/srp/form.py +++ b/srp/form.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals from django import forms from django.utils.translation import ugettext_lazy as _ @@ -30,4 +31,3 @@ class SrpFleetUpdateCostForm(forms.Form): class SrpFleetMainUpdateForm(forms.Form): fleet_aar_link = forms.CharField(required=True, label=_("After Action Report Link")) - diff --git a/srp/migrations/0001_initial.py b/srp/migrations/0001_initial.py new file mode 100644 index 00000000..661199cf --- /dev/null +++ b/srp/migrations/0001_initial.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.1 on 2016-09-05 21:40 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('eveonline', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='SrpFleetMain', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('fleet_name', models.CharField(default=b'', max_length=254)), + ('fleet_doctrine', models.CharField(default=b'', max_length=254)), + ('fleet_time', models.DateTimeField()), + ('fleet_srp_code', models.CharField(default=b'', max_length=254)), + ('fleet_srp_status', models.CharField(default=b'', max_length=254)), + ('fleet_srp_aar_link', models.CharField(default=b'', max_length=254)), + ('fleet_commander', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eveonline.EveCharacter')), + ], + ), + migrations.CreateModel( + name='SrpUserRequest', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('killboard_link', models.CharField(default=b'', max_length=254)), + ('after_action_report_link', models.CharField(default=b'', max_length=254)), + ('additional_info', models.CharField(default=b'', max_length=254)), + ('srp_status', models.CharField(default=b'', max_length=254)), + ('srp_total_amount', models.BigIntegerField(default=0)), + ('kb_total_loss', models.BigIntegerField(default=0)), + ('srp_ship_name', models.CharField(default=b'', max_length=254)), + ('post_time', models.DateTimeField(default=django.utils.timezone.now)), + ('character', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eveonline.EveCharacter')), + ('srp_fleet_main', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='srp.SrpFleetMain')), + ], + ), + ] diff --git a/srp/migrations/__init__.py b/srp/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/srp/models.py b/srp/models.py index c8e05e41..c57fa2ce 100755 --- a/srp/models.py +++ b/srp/models.py @@ -1,8 +1,11 @@ +from __future__ import unicode_literals +from django.utils.encoding import python_2_unicode_compatible from django.db import models from django.utils import timezone from eveonline.models import EveCharacter +@python_2_unicode_compatible class SrpFleetMain(models.Model): fleet_name = models.CharField(max_length=254, default="") fleet_doctrine = models.CharField(max_length=254, default="") @@ -16,6 +19,7 @@ class SrpFleetMain(models.Model): return self.fleet_name + " - SrpFleetMain" +@python_2_unicode_compatible class SrpUserRequest(models.Model): killboard_link = models.CharField(max_length=254, default="") after_action_report_link = models.CharField(max_length=254, default="") @@ -25,7 +29,7 @@ class SrpUserRequest(models.Model): character = models.ForeignKey(EveCharacter) srp_fleet_main = models.ForeignKey(SrpFleetMain) kb_total_loss = models.BigIntegerField(default=0) - srp_ship_name = models.CharField(max_length=254, default="") + srp_ship_name = models.CharField(max_length=254, default="") post_time = models.DateTimeField(default=timezone.now) def __str__(self): diff --git a/srp/views.py b/srp/views.py index 15c3a9ed..ade0c6d6 100755 --- a/srp/views.py +++ b/srp/views.py @@ -1,34 +1,37 @@ -from django.template import RequestContext -from django.http import HttpResponseRedirect -from django.shortcuts import render_to_response +from __future__ import unicode_literals +from django.shortcuts import render, redirect from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import permission_required -from django.contrib.auth.decorators import user_passes_test - -from util import random_string +from django.contrib import messages from eveonline.managers import EveManager -from authentication.managers import AuthServicesInfoManager -from util import check_if_user_has_permission -from models import SrpFleetMain -from models import SrpUserRequest -from form import SrpFleetMainForm -from form import SrpFleetUserRequestForm -from form import SrpFleetUpdateCostForm -from form import SrpFleetMainUpdateForm +from authentication.models import AuthServicesInfo +from srp.models import SrpFleetMain +from srp.models import SrpUserRequest +from srp.form import SrpFleetMainForm +from srp.form import SrpFleetUserRequestForm +from srp.form import SrpFleetUpdateCostForm +from srp.form import SrpFleetMainUpdateForm from services.managers.srp_manager import srpManager from notifications import notify from django.utils import timezone +from authentication.decorators import members_and_blues +import uuid import logging logger = logging.getLogger(__name__) -def srp_util_test(user): - return check_if_user_has_permission(user, 'member') or check_if_user_has_permission(user, 'blue_member') + +def random_string(string_length=10): + """Returns a random string of length string_length.""" + random = str(uuid.uuid4()) # Convert UUID format to a Python string. + random = random.upper() # Make all characters uppercase. + random = random.replace("-", "") # Remove the UUID '-'. + return random[0:string_length] # Return the random string. @login_required -@user_passes_test(srp_util_test) +@members_and_blues() def srp_management(request): logger.debug("srp_management called by user %s" % request.user) totalcost = 0 @@ -45,11 +48,11 @@ def srp_management(request): context = {"srpfleets": SrpFleetMain.objects.filter(fleet_srp_status=""), "totalcost": totalcost, "price_pair": price_pair} - return render_to_response('registered/srpmanagement.html', context, context_instance=RequestContext(request)) + return render(request, 'registered/srpmanagement.html', context=context) @login_required -@user_passes_test(srp_util_test) +@members_and_blues() def srp_management_all(request): logger.debug("srp_management_all called by user %s" % request.user) totalcost = 0 @@ -65,11 +68,11 @@ def srp_management_all(request): logger.debug("Determined all-time total SRP cost %s" % totalcost) context = {"srpfleets": SrpFleetMain.objects.all(), "totalcost": totalcost, "price_pair": price_pair} - return render_to_response('registered/srpmanagement.html', context, context_instance=RequestContext(request)) + return render(request, 'registered/srpmanagement.html', context=context) @login_required -@user_passes_test(srp_util_test) +@members_and_blues() def srp_fleet_view(request, fleet_id): logger.debug("srp_fleet_view called by user %s for fleet id %s" % (request.user, fleet_id)) if SrpFleetMain.objects.filter(id=fleet_id).exists(): @@ -83,11 +86,11 @@ def srp_fleet_view(request, fleet_id): "srpfleetrequests": SrpUserRequest.objects.filter(srp_fleet_main=fleet_main), "totalcost": totalcost} - return render_to_response('registered/srpfleetdata.html', context, context_instance=RequestContext(request)) - + return render(request, 'registered/srpfleetdata.html', context=context) else: - logger.error("Unable to view SRP fleet id %s for user %s - fleet matching id not found." % (fleet_id, request.user)) - return HttpResponseRedirect("/srp") + logger.error( + "Unable to view SRP fleet id %s for user %s - fleet matching id not found." % (fleet_id, request.user)) + return redirect("auth_srp_management_view") @login_required @@ -101,7 +104,7 @@ def srp_fleet_add_view(request): form = SrpFleetMainForm(request.POST) logger.debug("Request type POST contains form valid: %s" % form.is_valid()) if form.is_valid(): - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] character = EveManager.get_character_by_id(authinfo.main_char_id) srp_fleet_main = SrpFleetMain() @@ -116,6 +119,7 @@ def srp_fleet_add_view(request): completed = True completed_srp_code = srp_fleet_main.fleet_srp_code logger.info("Created SRP Fleet %s by user %s" % (srp_fleet_main.fleet_name, request.user)) + messages.success(request, 'Created SRP fleet %s.' % srp_fleet_main.fleet_name) else: logger.debug("Returning blank SrpFleetMainForm") @@ -123,7 +127,7 @@ def srp_fleet_add_view(request): render_items = {'form': form, "completed": completed, "completed_srp_code": completed_srp_code} - return render_to_response('registered/srpfleetadd.html', render_items, context_instance=RequestContext(request)) + return render(request, 'registered/srpfleetadd.html', context=render_items) @login_required @@ -134,9 +138,13 @@ def srp_fleet_remove(request, fleet_id): srpfleetmain = SrpFleetMain.objects.get(id=fleet_id) srpfleetmain.delete() logger.info("SRP Fleet %s deleted by user %s" % (srpfleetmain.fleet_name, request.user)) + messages.success(request, 'Removed SRP fleet %s.' % srpfleetmain.fleet_name) else: - logger.error("Unable to delete SRP fleet id %s for user %s - fleet matching id not found." % (fleet_id, request.user)) - return HttpResponseRedirect("/srp") + logger.error( + "Unable to delete SRP fleet id %s for user %s - fleet matching id not found." % (fleet_id, request.user)) + messages.error(request, 'Unable to locate SRP fleet with ID %s' % fleet_id) + return redirect("auth_srp_management_view") + @login_required @permission_required('auth.srp_management') @@ -147,9 +155,13 @@ def srp_fleet_disable(request, fleet_id): srpfleetmain.fleet_srp_code = "" srpfleetmain.save() logger.info("SRP Fleet %s disabled by user %s" % (srpfleetmain.fleet_name, request.user)) + messages.success(request, 'Disabled SRP fleet %s.' % srpfleetmain.fleet_name) else: - logger.error("Unable to disable SRP fleet id %s for user %s - fleet matching id not found." % (fleet_id, request.user)) - return HttpResponseRedirect("/srp") + logger.error( + "Unable to disable SRP fleet id %s for user %s - fleet matching id not found." % (fleet_id, request.user)) + messages.error(request, 'Unable to locate SRP fleet with ID %s' % fleet_id) + return redirect("auth_srp_management_view") + @login_required @permission_required('auth.srp_management') @@ -160,9 +172,13 @@ def srp_fleet_enable(request, fleet_id): srpfleetmain.fleet_srp_code = random_string(8) srpfleetmain.save() logger.info("SRP Fleet %s enable by user %s" % (srpfleetmain.fleet_name, request.user)) + messages.success(request, 'Enabled SRP fleet %s.' % srpfleetmain.fleet_name) else: - logger.error("Unable to enable SRP fleet id %s for user %s - fleet matching id not found." % (fleet_id, request.user)) - return HttpResponseRedirect("/srp") + logger.error( + "Unable to enable SRP fleet id %s for user %s - fleet matching id not found." % (fleet_id, request.user)) + messages.error(request, 'Unable to locate SRP fleet with ID %s' % fleet_id) + return redirect("auth_srp_management_view") + @login_required @permission_required('auth.srp_management') @@ -173,9 +189,12 @@ def srp_fleet_mark_completed(request, fleet_id): srpfleetmain.fleet_srp_status = "Completed" srpfleetmain.save() logger.info("Marked SRP Fleet %s as completed by user %s" % (srpfleetmain.fleet_name, request.user)) + messages.success(request, 'Marked SRP fleet %s as completed.' % srpfleetmain.fleet_name) else: - logger.error("Unable to mark SRP fleet with id %s as completed for user %s - fleet matching id not found." % (fleet_id, request.user)) - return HttpResponseRedirect("/srp_fleet_view/" + str(fleet_id)) + logger.error("Unable to mark SRP fleet with id %s as completed for user %s - fleet matching id not found." % ( + fleet_id, request.user)) + messages.error(request, 'Unable to locate SRP fleet with ID %s' % fleet_id) + return redirect("auth_srp_fleet_view", fleet_id) @login_required @@ -187,18 +206,21 @@ def srp_fleet_mark_uncompleted(request, fleet_id): srpfleetmain.fleet_srp_status = "" srpfleetmain.save() logger.info("Marked SRP Fleet %s as incomplete for user %s" % (fleet_id, request.user)) + messages.success(request, 'Marked SRP fleet %s as incomplete.' % srpfleetmain.fleet_name) + return redirect("auth_srp_fleet_view", fleet_id) else: - logger.error("Unable to mark SRP Fleet id %s as incomplete for user %s - fleet matching id not found." % (fleet_id, request.user)) - return HttpResponseRedirect("/srp_fleet_view/" + str(fleet_id)) + logger.error("Unable to mark SRP Fleet id %s as incomplete for user %s - fleet matching id not found." % ( + fleet_id, request.user)) + messages.error(request, 'Unable to locate SRP fleet with ID %s' % fleet_id) + return redirect('auth_srp_management_view') @login_required -@user_passes_test(srp_util_test) +@members_and_blues() def srp_request_view(request, fleet_srp): logger.debug("srp_request_view called by user %s for fleet srp code %s" % (request.user, fleet_srp)) completed = False no_srp_code = False - srp_code = "" if SrpFleetMain.objects.filter(fleet_srp_code=fleet_srp).exists() is False: no_srp_code = True @@ -209,7 +231,7 @@ def srp_request_view(request, fleet_srp): logger.debug("Request type POST contains form valid: %s" % form.is_valid()) if form.is_valid(): - authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + authinfo = AuthServicesInfo.objects.get_or_create(user=request.user)[0] character = EveManager.get_character_by_id(authinfo.main_char_id) srp_fleet_main = SrpFleetMain.objects.get(fleet_srp_code=fleet_srp) post_time = timezone.now() @@ -226,9 +248,12 @@ def srp_request_view(request, fleet_srp): srp_kill_link = srpManager.get_kill_id(srp_request.killboard_link) (srp_kill_data, ship_value) = srpManager.get_kill_data(srp_kill_link) except ValueError: - logger.debug("User %s Submitted Invalid Killmail Link %s or server could not be reached" % (request.user, srp_request.killboard_link)) - notify(request.user, "Your SRP request Killmail Link Failed Validation", message="Your SRP request Killmail link %s is invalid. Please make sure your using zKillboard." % srp_request.killboard_link, level="danger") - return HttpResponseRedirect("/srp") + logger.debug("User %s Submitted Invalid Killmail Link %s or server could not be reached" % ( + request.user, srp_request.killboard_link)) + # THIS SHOULD BE IN FORM VALIDATION + messages.error(request, + "Your SRP request Killmail link is invalid. Please make sure you are using zKillboard.") + return redirect("auth_srp_management_view") srp_ship_name = srpManager.get_ship_name(srp_kill_data) srp_request.srp_ship_name = srp_ship_name kb_total_loss = ship_value @@ -236,7 +261,9 @@ def srp_request_view(request, fleet_srp): srp_request.post_time = post_time srp_request.save() completed = True - logger.info("Created SRP Request on behalf of user %s for fleet name %s" % (request.user, srp_fleet_main.fleet_name)) + logger.info("Created SRP Request on behalf of user %s for fleet name %s" % ( + request.user, srp_fleet_main.fleet_name)) + messages.success(request, 'Submitted SRP request for your %s.' % srp_ship_name) else: logger.debug("Returning blank SrpFleetUserRequestForm") @@ -244,7 +271,7 @@ def srp_request_view(request, fleet_srp): render_items = {'form': form, "completed": completed, "no_srp_code": no_srp_code} - return render_to_response('registered/srpfleetrequest.html', render_items, context_instance=RequestContext(request)) + return render(request, 'registered/srpfleetrequest.html', context=render_items) @login_required @@ -258,12 +285,15 @@ def srp_request_remove(request, srp_request_id): stored_fleet_view = srpuserrequest.srp_fleet_main.id srpuserrequest.delete() logger.info("Deleted SRP request id %s for user %s" % (srp_request_id, request.user)) - + messages.success(request, 'Deleted SRP request from %s for their %s.' % ( + srpuserrequest.character, srpuserrequest.srp_ship_name)) if stored_fleet_view is None: - logger.error("Unable to delete srp request id %s for user %s - request matching id not found." % (srp_request_id, request.user)) - return HttpResponseRedirect("/srp") + logger.error("Unable to delete srp request id %s for user %s - request matching id not found." % ( + srp_request_id, request.user)) + messages.error(request, 'Unable to locate SRP request with ID %s' % srp_request_id) + return redirect("auth_srp_management_view") else: - return HttpResponseRedirect("/srp_fleet_view/" + str(stored_fleet_view)) + return redirect("auth_srp_fleet_view", stored_fleet_view) @login_required @@ -272,8 +302,6 @@ def srp_request_approve(request, srp_request_id): logger.debug("srp_request_approve called by user %s for srp request id %s" % (request.user, srp_request_id)) stored_fleet_view = None - - if SrpUserRequest.objects.filter(id=srp_request_id).exists(): srpuserrequest = SrpUserRequest.objects.get(id=srp_request_id) stored_fleet_view = srpuserrequest.srp_fleet_main.id @@ -281,13 +309,24 @@ def srp_request_approve(request, srp_request_id): if srpuserrequest.srp_total_amount == 0: srpuserrequest.srp_total_amount = srpuserrequest.kb_total_loss srpuserrequest.save() - logger.info("Approved SRP request id %s for character %s by user %s" % (srp_request_id, srpuserrequest.character, request.user)) - + logger.info("Approved SRP request id %s for character %s by user %s" % ( + srp_request_id, srpuserrequest.character, request.user)) + messages.success(request, 'Approved SRP request from %s for their %s.' % ( + srpuserrequest.character, srpuserrequest.srp_ship_name)) + notify( + srpuserrequest.character.user, + 'SRP Request Approved', + level='success', + message='Your SRP request for a %s lost during %s has been approved for %s ISK.' % ( + srpuserrequest.srp_ship_name, srpuserrequest.srp_fleet_main.fleet_name, srpuserrequest.srp_total_amount) + ) if stored_fleet_view is None: - logger.error("Unable to approve srp request id %s on behalf of user %s - request matching id not found." % (srp_request_id, request.user)) - return HttpResponseRedirect("/srp") + logger.error("Unable to approve srp request id %s on behalf of user %s - request matching id not found." % ( + srp_request_id, request.user)) + messages.error(request, 'Unable to locate SRP request with ID %s' % srp_request_id) + return redirect("auth_srp_management_view") else: - return HttpResponseRedirect("/srp_fleet_view/" + str(stored_fleet_view)) + return redirect("auth_srp_fleet_view", stored_fleet_view) @login_required @@ -301,25 +340,37 @@ def srp_request_reject(request, srp_request_id): stored_fleet_view = srpuserrequest.srp_fleet_main.id srpuserrequest.srp_status = "Rejected" srpuserrequest.save() - logger.info("SRP request id %s for character %s rejected by %s" % (srp_request_id, srpuserrequest.character, request.user)) + logger.info("SRP request id %s for character %s rejected by %s" % ( + srp_request_id, srpuserrequest.character, request.user)) + messages.success(request, 'Rejected SRP request from %s for their %s.' % ( + srpuserrequest.character, srpuserrequest.srp_ship_name)) + notify( + srpuserrequest.character.user, + 'SRP Request Rejected', + level='danger', + message='Your SRP request for a %s lost during %s has been rejected.' % ( + srpuserrequest.srp_ship_name, srpuserrequest.srp_fleet_main.fleet_name) + ) if stored_fleet_view is None: - logger.error("Unable to reject SRP request id %s on behalf of user %s - request matching id not found." % (srp_request_id, request.user)) - return HttpResponseRedirect("/srp") + logger.error("Unable to reject SRP request id %s on behalf of user %s - request matching id not found." % ( + srp_request_id, request.user)) + messages.error(request, 'Unable to locate SRP request with ID %s' % srp_request_id) + return redirect("auth_srp_management_view") else: - return HttpResponseRedirect("/srp_fleet_view/" + str(stored_fleet_view)) + return redirect("auth_srp_fleet_view", stored_fleet_view) @login_required @permission_required('auth.srp_management') def srp_request_update_amount_view(request, fleet_srp_request_id): - logger.debug("srp_request_update_amount_view called by user %s for fleet srp request id %s" % (request.user, fleet_srp_request_id)) - no_srp_code = False - srp_code = "" + logger.debug("srp_request_update_amount_view called by user %s for fleet srp request id %s" % ( + request.user, fleet_srp_request_id)) if SrpUserRequest.objects.filter(id=fleet_srp_request_id).exists() is False: logger.error("Unable to locate SRP request id %s for user %s" % (fleet_srp_request_id, request.user)) - no_srp_code = True + messages.error(request, 'Unable to locate SRP request with ID %s' % fleet_srp_request_id) + return redirect("auth_srp_management_view") if request.method == 'POST': form = SrpFleetUpdateCostForm(request.POST) @@ -328,17 +379,17 @@ def srp_request_update_amount_view(request, fleet_srp_request_id): srp_request = SrpUserRequest.objects.get(id=fleet_srp_request_id) srp_request.srp_total_amount = form.cleaned_data['srp_total_amount'] srp_request.save() - logger.info("Updated srp request id %s total to %s by user %s" % (fleet_srp_request_id, form.cleaned_data['srp_total_amount'], request.user)) - - return HttpResponseRedirect("/srp_fleet_view/" + str(srp_request.srp_fleet_main.id)) + logger.info("Updated srp request id %s total to %s by user %s" % ( + fleet_srp_request_id, form.cleaned_data['srp_total_amount'], request.user)) + messages.success(request, 'Updated SRP amount.') + return redirect("auth_srp_fleet_view", srp_request.srp_fleet_main.id) else: logger.debug("Returning blank SrpFleetUpdateCostForm") form = SrpFleetUpdateCostForm() - render_items = {'form': form, "no_srp_code": no_srp_code} + render_items = {'form': form} - return render_to_response('registered/srpfleetrequestamount.html', render_items, - context_instance=RequestContext(request)) + return render(request, 'registered/srpfleetrequestamount.html', context=render_items) @login_required @@ -346,7 +397,6 @@ def srp_request_update_amount_view(request, fleet_srp_request_id): def srp_fleet_edit_view(request, fleet_id): logger.debug("srp_fleet_edit_view called by user %s for fleet id %s" % (request.user, fleet_id)) no_fleet_id = False - form = None if SrpFleetMain.objects.filter(id=fleet_id).exists(): if request.method == 'POST': form = SrpFleetMainUpdateForm(request.POST) @@ -356,15 +406,16 @@ def srp_fleet_edit_view(request, fleet_id): srpfleetmain.fleet_srp_aar_link = form.cleaned_data['fleet_aar_link'] srpfleetmain.save() logger.info("User %s edited SRP Fleet %s" % (request.user, srpfleetmain.fleet_name)) - return HttpResponseRedirect("/srp") + messages.success(request, 'Saved changes to SRP fleet %s' % srpfleetmain.fleet_name) + return redirect("auth_srp_management_view") else: logger.debug("Returning blank SrpFleetMainUpdateForm") form = SrpFleetMainUpdateForm() + render_items = {'form': form, "no_fleet_id": no_fleet_id} + return render(request, 'registered/srpfleetupdate.html', context=render_items) + else: - logger.error("Unable to edit srp fleet id %s for user %s - fleet matching id not found." % (fleet_id, request.user)) - no_fleet_id = True - - render_items = {'form': form, "no_fleet_id": no_fleet_id} - - return render_to_response('registered/srpfleetupdate.html', render_items, - context_instance=RequestContext(request)) + logger.error( + "Unable to edit srp fleet id %s for user %s - fleet matching id not found." % (fleet_id, request.user)) + messages.error(request, 'Unable to locate SRP fleet with ID %s' % fleet_id) + return redirect("auth_srp_management_view") diff --git a/stock/static/img/sso/EVE_SSO_Login_Buttons_Large_Black.png b/stock/static/img/sso/EVE_SSO_Login_Buttons_Large_Black.png new file mode 100644 index 0000000000000000000000000000000000000000..0540f9a3d88b33be475dbcdec8329523791c3263 GIT binary patch literal 2308 zcmV+f3H$bmP)6~}+GUQ(fUrxaC)vYS>F(0DcoXg=&ZPyrEkK!``=sA>qRl7do_QaerUil>4i zBt(cHaiSI|O6?Ruk&-y&CDJ5>hXj6nDJ}IbNPwVTqachLPl6n1yq6F6&hET-*538* z#QCqZJ9FmTbI&>V+;bl@v)bAOUtcxQ!F8+z2(-|13-ebQWJp{4)jL0bJEGNEM}kIz za!hoMHzp+1`2;qCb-aQO(H{PjpfQ5T3h9) z<<&+o3wI>i$pN*X)k$9(+RHP`t<3_ED7V_`y5O&EGac8Qz>5RQB-<-_hC{IY$v!^b zX*4tvtybYW+84<<^$kIJ5t$=SxpDDmhLuSXBiD&Vtybb=-%`+cD@EKghgczbpgoWb zS^+Et&1%3hWwa*f+y0if!V*X{W2x3W2etbk*xuUJYfDnZY9%j7#7f`zLZeB;O0yuh z&*P(S+>s1RgcA`2{D#MPh;0Durd5gu3=(BFY0+)E4F9Ub+5k@^6ALA_m zJkDjJPT3ZKX>?47c7g>oUwtLgbOYy@vC(pLlL00;g{f%0$KK_BptgSO41jir-eJ3EI?uEJ^AkSAs1Ip!+wwaJNIQWTk_4})_NwD&?I za9FWZzr(LXgj@#TXWUB`*u@z|v5-;@EAUerwa8a$s`q;ztwd<qx^Z7fLnRbNO>8G_yP0jKD$ z$OC6^_}Sz}H#v?li9s&XALYlu zEBtX0>MqpS=Md_<%JDF8md|4FeGE1+g26W6FeB`zhi#6bPN>pSj=^orRA{wOU>9;u z*&w5XYyChy7y;~xOr%*`P@ zmz8NRaGDPSTR6$zDp&91J^+4RnOMHUs{pJCRqam!^!m)qqXVNrkqPqT86gkA2rxZ4Q;%J?r5$9Dxdfo()9`*a z^`cWGO%Eocj!a>o12euH+sOkHj0Ox%iSX6RGZ7l#S3IhYhSlnnjA2>pOuZOP#H zqMB5v*%eY-QE4ajE7WOI4|z;gPo9t38oP%)hneu<*iVl-%LiyCNLVAe-zOR@?h7hK zzl(P($~~+HV3-SwlfD4Q?=uWC&fw1*XH8>>74yw~#o7o7!kf)zo<kj&L+FStUd}Bb644ePUy@($$>2u9$n1AsH zhrsD2QI$ey@RkQpV_WH;)Re2d`P+CF*+5LtJ#3;d$ zXWC{{{g7S&_#s&yWZZ{GbKjM%|6vvHCeI;yRA~H%L!PVA>x)O zV?B?MB1;B1PMOm@0_^2DpYrH$-vkqsxyW(u_1HMYdSHq&Q*@~#t8VM)lcYFUkzc)L z*Yic2o-n4)3S6x4bX9nERIb0|W0QB=O$7W}9H-e!mIsgl`I3)MH6Rg|s4qwO%zMPn zR+{HY{_VLsA4zHug72&NV}LPq_V58r_Av&O*au|TgURul<;MeQCRQ(Y_uUhi=#hu6 zs^?|%kJaS#+9b=@1CxE2>|qbEFJKc)psf*&e>-6nKVdb~d|2&X-*UnR-wd|ay zVeiU1CyM7e)bP-N#Xs!RxTiqcAvBifnHGU|mx#~fGacN*r50z7dJ)%5qj4o}uS3?i zlwB@_=@hrnu-g)=zhIDWuCyQG}fVS`B#_o-`c7JmvE{NjAm<7kx6%`zhP^ z<3yY8bJTA~98f0tzwc@H*ZOno=8TJrlX`7TNZa2A0gq{`S8+=FP~(-YZyDC=MccKH ex;^||cK#m|2h2&6XR)CG0000~wnwpxLnwpG^jGCI7nwpx5ii(VkjEahinwpx5ii(<=nkp(PD=RB4EiEuG zFflPPGcz+ZG&D6eH8wUjI5;>vJ3Br;K0!f2LPA1ALqkMFL`XQ&?D7Sy@?HT3TCMTVG#aU|?WlV`F4wWMyS#W@ct*XJ>0`Yiw+6Z*OmK zaBy*PadmZdcXxMqczAnzdwhI+f`WpBgM);GgoTBLhK7cRhlhxWh>3}bi;IhljEs$q zjgF3vkB^U#kdTp)k&=>sxVgExy1Kf%ySu!+yuH1>zP`S{zrVo1z`?=6!otGC!^6bH z#KpzM#>U3S$H&OX$jQmc%gf8m%*@Tr&Cbrw&(F`$(9qG*(bCe=)YR0~)z#M4*4Nk9 z*x1%u`j&YNupW-}@WjD>ll;!&0ACyHVaY=` z8HkIHLh{()-DEJHzz-+SC6JCD(r?BA_VC&{^O;0-qgkJgi;k7aUNdnJbX4Pjxpu8k zO&rWKE_r2zHe3Sdpb+T4&8p)(1^orYr4$iyqq}N<@>~(S8gbvR0 z$MfC`{%Ua~7`LctMYmgxrTQ9!ay5m$qYd?6~2BLNsW6G3`5>5?9EaCwuCeJ5D}=Ku_+zD zk%AorZjt>h8&=RdigCa9+TUS&6whM=16S;I;Vc*b2=+$+Mr1>QL-r&!@~@YmNTQmBF`Z@ za;}>mqNARP$}vh=(&2tQLl$bmTFLA{32wWFE4Kit%&^$X1C}GT!0g4!H8EI&nK}g4!zR z2o=j*1ozzwJ(%YwCe+Rwa6jrAh+{3!Ufrlzpr#hXfnuR$P}Eu}CU0Q9SX={E5~Ygh_$A&!dcv=C`TR`NmmB^Gz|N_i z0H1Q#a4DZ3+Ti_j>GpIh#p0R$VzE$BykhBtOdFISn}I%AEb?bA{f&CDc+sv*T-V{Fzgw8qqi6DUTa1N zmU+pt+8|{eMNNp((TNjqzfuY3s#r=og#$LDLqifppdcOfOdHUVX}F2_WC^{}MFru2 zf9WgP{o3yyh`I)M9i6*V!MH;JL*k4Nj1JRG!55|~EWX*qVnGWv%cAz(A@7M6szFMQ z7A~ropByCjf7M#XA(6f8MsYWXtAR|lfuiAmgrNiWndUxk26EP?NOwz8inxQn4cKwV z?`|xmmQ%joAf@ga6d!V0R_Ge)UrJN_Ri-DUoVWQ>D0DF=mabXuOR17;CZ(D?ZCubY zZ&m7t^fIk0rE}uZgp1kwG*6MUAv$(Oa5%ImuB-6jsB4gp#q!OjbjXFYqI-+zR9hn* zg&G~=IVzkqkB)+ZSJt6JP{;fyix;w%X zGF-W^Dt;p_lr~L(Q>X;B<5B3a`l03hPiL`mD|vf^NXMB+a6jI%r{h#^Cy4y7RL{haCqjyIQf6hm#~9 zizsn>;eG<8^d#wuMU!lYEhJA#7m<$8Py7ihq~2U))vb#4^x&Kzr{mEMhnxTFH+w8* z1s(Bdhs9X}wc`Zoh$phc`BVE6TXz%RBCk)yq@@YO_{-#lH~KC<>lobBuq7zG_S}CF WhP*NH8;&~w0000 @@ -30,6 +31,10 @@ #f_lang_select { margin-right: 5px; } + .navbar-brand { + height: 58px; + padding: 19px 19px; + } @@ -39,22 +44,17 @@