diff --git a/alliance_auth/settings.py.example b/alliance_auth/settings.py.example index 2aa364b2..a6a7e6a8 100644 --- a/alliance_auth/settings.py.example +++ b/alliance_auth/settings.py.example @@ -35,7 +35,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) SECRET_KEY = '' # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = 'True' == os.environ.get('AA_DEBUG','True') +DEBUG = True ALLOWED_HOSTS = [] @@ -144,22 +144,13 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'alliance_auth', - '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'), + 'USER': 'allianceserver', + 'PASSWORD': '', + 'HOST': '127.0.0.1', + 'PORT': '3306', }, } -# If you have run the authentication.0013_service_modules migration -# you will need to set this to True in order to install service modules -# which were involved in that migration after it has been run. -# If you are on a fresh install with no existing database you can safely -# set this to True -# If you have not run the authentication.0013_service_modules migration -# leave this set to False. -SERVICES_MIGRATED = False - # Password validation # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators @@ -178,16 +169,15 @@ AUTH_PASSWORD_VALIDATORS = [ }, ] +AUTHENTICATION_BACKENDS = ['authentication.backends.StateBackend', 'authentication.backends.ModelBackend'] LOGIN_URL = 'auth_login_user' -SUPERUSER_STATE_BYPASS = 'True' == os.environ.get('AA_SUPERUSER_STATE_BYPASS', 'True') - # Internationalization # https://docs.djangoproject.com/en/1.10/topics/i18n/ -LANGUAGE_CODE = os.environ.get('AA_LANGUAGE_CODE', 'en-us') +LANGUAGE_CODE = 'en-us' -TIME_ZONE = os.environ.get('AA_TIME_ZONE', 'UTC') +TIME_ZONE = 'UTC' USE_I18N = True @@ -227,35 +217,27 @@ CACHES = { ## ##################################################### +#################### +# SITE_NAME - Name of the auth site. +#################### +SITE_NAME = 'Alliance Auth' + ################# # EMAIL SETTINGS ################# -# DOMAIN - The alliance auth domain_url +# DOMAIN - The Alliance Auth domain (or subdomain) address, starting with http:// # EMAIL_HOST - SMTP Server URL # EMAIL_PORT - SMTP Server PORT # EMAIL_HOST_USER - Email Username (for gmail, the entire address) # EMAIL_HOST_PASSWORD - Email Password # EMAIL_USE_TLS - Set to use TLS encryption ################# -DOMAIN = os.environ.get('AA_DOMAIN', 'https://example.com') -EMAIL_HOST = os.environ.get('AA_EMAIL_HOST', 'smtp.gmail.com') -EMAIL_PORT = int(os.environ.get('AA_EMAIL_PORT', '587')) -EMAIL_HOST_USER = os.environ.get('AA_EMAIL_HOST_USER', '') -EMAIL_HOST_PASSWORD = os.environ.get('AA_EMAIL_HOST_PASSWORD', '') -EMAIL_USE_TLS = 'True' == os.environ.get('AA_EMAIL_USE_TLS', 'True') - -#################### -# Front Page Links -#################### -# KILLBOARD_URL - URL for your killboard. Blank to hide link -# MEDIA_URL - URL for your media page (youtube etc). Blank to hide link -# FORUM_URL - URL for your forums. Blank to hide link -# SITE_NAME - Name of the auth site. -#################### -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', '') -SITE_NAME = os.environ.get('AA_SITE_NAME', 'Alliance Auth') +DOMAIN = 'https://example.com' +EMAIL_HOST = 'smtp.gmail.com' +EMAIL_PORT = 587 +EMAIL_HOST_USER = '' +EMAIL_HOST_PASSWORD = '' +EMAIL_USE_TLS = True ################### # SSO Settings @@ -264,174 +246,100 @@ SITE_NAME = os.environ.get('AA_SITE_NAME', 'Alliance Auth') # https://developers.eveonline.com/ # Callback URL should be https://example.com/sso/callback ################### -ESI_SSO_CLIENT_ID = os.environ.get('AA_ESI_SSO_CLIENT_ID', '') -ESI_SSO_CLIENT_SECRET = os.environ.get('AA_ESI_SSO_CLIENT_SECRET', '') -ESI_SSO_CALLBACK_URL = os.environ.get('AA_ESI_SSO_CALLBACK_URL', '') +ESI_SSO_CLIENT_ID = '' +ESI_SSO_CLIENT_SECRET = '' +ESI_SSO_CALLBACK_URL = '' -######################### -# Default Group Settings -######################### -# DEFAULT_AUTH_GROUP - Default group members are put in -# DEFAULT_BLUE_GROUP - Default group for blue members -# MEMBER_CORP_GROUPS - Assign members to a group representing their main corp -# BLUE_CORP_GROUPS - Assign blues to a group representing their main corp -######################### -DEFAULT_AUTH_GROUP = os.environ.get('AA_DEFAULT_ALLIANCE_GROUP', 'Member') -DEFAULT_BLUE_GROUP = os.environ.get('AA_DEFAULT_BLUE_GROUP', 'Blue') -MEMBER_CORP_GROUPS = 'True' == os.environ.get('AA_MEMBER_CORP_GROUPS', 'True') -MEMBER_ALLIANCE_GROUPS = 'True' == os.environ.get('AA_MEMBER_ALLIANCE_GROUPS', 'False') -BLUE_CORP_GROUPS = 'True' == os.environ.get('AA_BLUE_CORP_GROUPS', 'False') -BLUE_ALLIANCE_GROUPS = 'True' == os.environ.get('AA_BLUE_ALLIANCE_GROUPS', 'False') - -######################### -# Tenant Configuration -######################### -# CORP_IDS - A list of corporation IDs to treat as members. -# ALLIANCE_IDS - A list of alliance IDs to treat as members. -# Any corps in a specified alliance will be treated as members, so do not include them in CORP_IDS -######################### -CORP_IDS = [] -ALLIANCE_IDS = [] - -######################### -# Standings Configuration -######################### -# Add a corp API key to add blue standings to grant access. -# CORP_API_ID - Set this to the api id for the corp API key -# CORP_API_VCODE - Set this to the api vcode for the corp API key -# BLUE_STANDING - The lowest standings value to consider blue -# STANDING_LEVEL - The level of standings to query. Accepted values are 'corp' and 'alliance'. -# BLUE_CORP_IDS - A list of corps to remain blue regardless of in-game standings -# BLUE_ALLIANCE_IDS - A list of alliances to remain blue regardless of in-game standings -######################## -CORP_API_ID = os.environ.get('AA_CORP_API_ID', '') -CORP_API_VCODE = os.environ.get('AA_CORP_API_VCODE', '') -BLUE_STANDING = float(os.environ.get('AA_BLUE_STANDING', '5.0')) -STANDING_LEVEL = os.environ.get('AA_STANDING_LEVEL', 'corp') -BLUE_CORP_IDS = [] -BLUE_ALLIANCE_IDS = [] - -######################## -# API Configuration -######################## -# MEMBER_API_MASK - Numeric value of minimum API mask required for members -# MEMBER_API_ACCOUNT - Require API to be for Account and not character restricted -# BLUE_API_MASK - Numeric value of minimum API mask required for blues -# BLUE_API_ACCOUNT - Require API to be for Account and not character restricted -# REJECT_OLD_APIS - Require each submitted API be newer than the latest submitted API -# REJECT_OLD_APIS_MARGIN - Margin from latest submitted API ID within which a newly submitted API is still accepted -# API_SSO_VALIDATION - Require users to prove ownership of newly entered API keys via SSO -# Requires SSO to be configured. -####################### -MEMBER_API_MASK = os.environ.get('AA_MEMBER_API_MASK', 268435455) -MEMBER_API_ACCOUNT = 'True' == os.environ.get('AA_MEMBER_API_ACCOUNT', 'True') -BLUE_API_MASK = os.environ.get('AA_BLUE_API_MASK', 8388608) -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) -API_SSO_VALIDATION = 'True' == os.environ.get('AA_API_SSO_VALIDATION', 'False') - -####################### -# EVE Provider Settings -####################### -# EVEONLINE_CHARACTER_PROVIDER - Name of default data source for getting eve character data -# EVEONLINE_CORP_PROVIDER - Name of default data source for getting eve corporation data -# EVEONLINE_ALLIANCE_PROVIDER - Name of default data source for getting eve alliance data -# EVEONLINE_ITEMTYPE_PROVIDER - Name of default data source for getting eve item type data -# -# Available sources are 'esi' and 'xml'. Leaving blank results in the default 'esi' being used. -####################### -EVEONLINE_CHARACTER_PROVIDER = os.environ.get('AA_EVEONLINE_CHARACTER_PROVIDER', '') -EVEONLINE_CORP_PROVIDER = os.environ.get('AA_EVEONLINE_CORP_PROVIDER', '') -EVEONLINE_ALLIANCE_PROVIDER = os.environ.get('AA_EVEONLINE_ALLIANCE_PROVIDER', '') -EVEONLINE_ITEMTYPE_PROVIDER = os.environ.get('AA_EVEONLINE_ITEMTYPE_PROVIDER', '') +################# +# Login Settings +################# +# Both of these redirects accept values as per the django redirect shortcut +# https://docs.djangoproject.com/en/1.10/topics/http/shortcuts/#redirect +# - url names eg 'authentication:dashboard' +# - relative urls eg '/dashboard' +# - absolute urls eg 'http://example.com/dashboard' +# LOGIN_REDIRECT_URL - default destination when logging in if no redirect specified +# LOGOUT_REDIRECT_URL - destination after logging out +# LOGIN_TOKEN_SCOPES - scopes required on new tokens when logging in. Cannot be blank. +################## +LOGIN_REDIRECT_URL = 'authentication:dashboard' +LOGOUT_REDIRECT_URL = 'authentication:dashboard' +LOGIN_TOKEN_SCOPES = ['esi-characters.read_opportunities.v1'] ##################### # Alliance Market ##################### -MARKET_URL = os.environ.get('AA_MARKET_URL', 'http://example.com/market') +MARKET_URL = 'http://example.com/market' MARKET_DB = { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'alliance_market', - 'USER': os.environ.get('AA_DB_MARKET_USER', 'allianceserver-market'), - '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'), + 'USER': 'allianceserver-market', + 'PASSWORD': '', + 'HOST': '127.0.0.1', + 'PORT': '3306', } ##################### -# HR Configuration -##################### -# API_KEY_AUDIT_URL - URL for viewing API keys. -# Other URLs are supported. Use string formatting notation {} with parameter names api_id, vcode, pk -# Example URL formats are shown below: -# Old Jacknife: 'https://example.com/jacknife/eveapi/audit.php?usid={api_id}&apik={vcode}' -# New Jacknife: 'https://example.com/jacknife/?usid={api_id}&apik={vcode}' -# SeAT: 'https://seat.example.com/api-key/detail/{api_id}' -# Django Admin: '/admin/eveonline/eveapikeypair/{pk}/change' -# Leave blank for the verification code to be shown in a popup on click. -##################### -API_KEY_AUDIT_URL = os.environ.get('AA_API_KEY_AUDIT_URL', '') - -##################### -# Forum Configuration +# IPBoard3 Configuration ##################### # IPBOARD_ENDPOINT - Api endpoint if using ipboard # IPBOARD_APIKEY - Api key to interact with ipboard # IPBOARD_APIMODULE - Module for alliance auth *leave alone* ##################### -IPBOARD_ENDPOINT = os.environ.get('AA_IPBOARD_ENDPOINT', 'example.com/interface/board/index.php') -IPBOARD_APIKEY = os.environ.get('AA_IPBOARD_APIKEY', 'somekeyhere') +IPBOARD_ENDPOINT = 'example.com/interface/board/index.php' +IPBOARD_APIKEY = '' IPBOARD_APIMODULE = 'aa' ######################## # XenForo Configuration ######################## -XENFORO_ENDPOINT = os.environ.get('AA_XENFORO_ENDPOINT', 'example.com/api.php') -XENFORO_DEFAULT_GROUP = os.environ.get('AA_XENFORO_DEFAULT_GROUP', 0) -XENFORO_APIKEY = os.environ.get('AA_XENFORO_APIKEY', 'yourapikey') +XENFORO_ENDPOINT = 'example.com/api.php' +XENFORO_DEFAULT_GROUP = 0 +XENFORO_APIKEY = '' ##################### ###################### # Jabber Configuration ###################### -# JABBER_URL - Jabber address url +# JABBER_URL - Jabber address url, no leading http:// # JABBER_PORT - Jabber service portal -# JABBER_SERVER - Jabber server url +# JABBER_SERVER - Jabber server url (server name, eg 'example.com'), no leading http:// # OPENFIRE_ADDRESS - Address of the openfire admin console including port -# Please use http with 9090 or https with 9091 +# Please use http:// with 9090 or https:// with 9091 +# eg 'http://example.com:9090' or 'https://example.com:9091' # OPENFIRE_SECRET_KEY - Openfire REST API secret key -# BROADCAST_USER - Broadcast user JID +# BROADCAST_USER - Broadcast user username (before @ sign) # BROADCAST_USER_PASSWORD - Broadcast user password +# BROADCAST_SERVICE_NAME - Name of the Openfire service to broadcast to, usually "broadcast" ###################### -JABBER_URL = os.environ.get('AA_JABBER_URL', "example.com") -JABBER_PORT = int(os.environ.get('AA_JABBER_PORT', '5223')) -JABBER_SERVER = os.environ.get('AA_JABBER_SERVER', "example.com") -OPENFIRE_ADDRESS = os.environ.get('AA_OPENFIRE_ADDRESS', "http://example.com:9090") -OPENFIRE_SECRET_KEY = os.environ.get('AA_OPENFIRE_SECRET_KEY', "somekey") -BROADCAST_USER = os.environ.get('AA_BROADCAST_USER', "broadcast@") + JABBER_URL -BROADCAST_USER_PASSWORD = os.environ.get('AA_BROADCAST_USER_PASSWORD', "somepassword") -BROADCAST_SERVICE_NAME = os.environ.get('AA_BROADCAST_SERVICE_NAME', "broadcast") +JABBER_URL = '' +JABBER_PORT = 5223 +JABBER_SERVER = '' +OPENFIRE_ADDRESS = '' +OPENFIRE_SECRET_KEY = '' +BROADCAST_USER = "broadcast" + "@" + JABBER_URL +BROADCAST_USER_PASSWORD = '' +BROADCAST_SERVICE_NAME = "broadcast" ###################################### # Mumble Configuration ###################################### -# MUMBLE_URL - Mumble server url -# MUMBLE_SERVER_ID - Mumble server id +# MUMBLE_URL - Mumble server url, tolerates leading http://, mumble://, or none +# eg 'http://example.com', 'mumble://example.com', or 'example.com' ###################################### -MUMBLE_URL = os.environ.get('AA_MUMBLE_URL', "https://example.com") -MUMBLE_SERVER_ID = int(os.environ.get('AA_MUMBLE_SERVER_ID', '1')) +MUMBLE_URL = '' ###################################### # PHPBB3 Configuration ###################################### +PHPBB3_URL = 'http://example.com/phpbb/' PHPBB3_DB = { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'alliance_forum', - 'USER': os.environ.get('AA_DB_PHPBB3_USER', 'allianceserver-phpbb3'), - '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'), + 'USER': 'allianceserver-phpbb3', + 'PASSWORD': '', + 'HOST': '127.0.0.1', + 'PORT': '3306', } ###################################### @@ -445,82 +353,86 @@ PHPBB3_DB = { # TEAMSPEAK3_AUTHED_GROUP_ID - Default authed group id # TEAMSPEAK3_PUBLIC_URL - teamspeak3 public url used for link creation ###################################### -TEAMSPEAK3_SERVER_IP = os.environ.get('AA_TEAMSPEAK3_SERVER_IP', '127.0.0.1') -TEAMSPEAK3_SERVER_PORT = int(os.environ.get('AA_TEAMSPEAK3_SERVER_PORT', '10011')) -TEAMSPEAK3_SERVERQUERY_USER = os.environ.get('AA_TEAMSPEAK3_SERVERQUERY_USER', 'serveradmin') -TEAMSPEAK3_SERVERQUERY_PASSWORD = os.environ.get('AA_TEAMSPEAK3_SERVERQUERY_PASSWORD', 'passwordhere') -TEAMSPEAK3_VIRTUAL_SERVER = int(os.environ.get('AA_TEAMSPEAK3_VIRTUAL_SERVER', '1')) -TEAMSPEAK3_PUBLIC_URL = os.environ.get('AA_TEAMSPEAK3_PUBLIC_URL', 'example.com') +TEAMSPEAK3_SERVER_IP = '127.0.0.1' +TEAMSPEAK3_SERVER_PORT = 10011 +TEAMSPEAK3_SERVERQUERY_USER = 'serveradmin' +TEAMSPEAK3_SERVERQUERY_PASSWORD = '' +TEAMSPEAK3_VIRTUAL_SERVER = 1 +TEAMSPEAK3_PUBLIC_URL = '' ###################################### # Discord Configuration ###################################### # DISCORD_GUILD_ID - ID of the guild to manage -# DISCORD_BOT_TOKEN - oauth token of the app bot user -# DISCORD_INVITE_CODE - invite code to the server -# DISCORD_APP_ID - oauth app client ID -# DISCORD_APP_SECRET - oauth app secret -# DISCORD_CALLBACK_URL - oauth callback url -# DISCORD_SYNC_NAMES - enable to force discord nicknames to be set to eve char name (bot needs Manage Nicknames permission) +# DISCORD_BOT_TOKEN - OAuth token of the app bot user +# DISCORD_INVITE_CODE - Alphanumeric string invite code to the server +# Do not include the leading http://discord.gg/ +# DISCORD_APP_ID - OAuth app client ID +# DISCORD_APP_SECRET - OAuth app secret +# DISCORD_CALLBACK_URL - OAuth callback url +# Should be of the form 'http://example.com/discord/callback' +# DISCORD_SYNC_NAMES - Force discord nicknames to be set to eve char name ###################################### -DISCORD_GUILD_ID = os.environ.get('AA_DISCORD_GUILD_ID', '') -DISCORD_BOT_TOKEN = os.environ.get('AA_DISCORD_BOT_TOKEN', '') -DISCORD_INVITE_CODE = os.environ.get('AA_DISCORD_INVITE_CODE', '') -DISCORD_APP_ID = os.environ.get('AA_DISCORD_APP_ID', '') -DISCORD_APP_SECRET = os.environ.get('AA_DISCORD_APP_SECRET', '') -DISCORD_CALLBACK_URL = os.environ.get('AA_DISCORD_CALLBACK_URL', 'http://example.com/discord/callback') -DISCORD_SYNC_NAMES = 'True' == os.environ.get('AA_DISCORD_SYNC_NAMES', 'False') +DISCORD_GUILD_ID = '' +DISCORD_BOT_TOKEN = '' +DISCORD_INVITE_CODE = '' +DISCORD_APP_ID = '' +DISCORD_APP_SECRET = '' +DISCORD_CALLBACK_URL = '' +DISCORD_SYNC_NAMES = False ###################################### # Discourse Configuration ###################################### -# DISCOURSE_URL - Web address of the forums (no trailing slash) +# DISCOURSE_URL - Web address of the forums (no trailing slash). Include http:// # DISCOURSE_API_USERNAME - API account username # DISCOURSE_API_KEY - API Key # DISCOURSE_SSO_SECRET - SSO secret key ###################################### -DISCOURSE_URL = os.environ.get('AA_DISCOURSE_URL', '') -DISCOURSE_API_USERNAME = os.environ.get('AA_DISCOURSE_API_USERNAME', '') -DISCOURSE_API_KEY = os.environ.get('AA_DISCOURSE_API_KEY', '') -DISCOURSE_SSO_SECRET = os.environ.get('AA_DISCOURSE_SSO_SECRET', '') +DISCOURSE_URL = '' +DISCOURSE_API_USERNAME = '' +DISCOURSE_API_KEY = '' +DISCOURSE_SSO_SECRET = '' ##################################### # IPS4 Configuration ##################################### -# IPS4_URL - base url of the IPS4 install (no trailing slash) +# IPS4_URL - Base URL of the IPS4 install (no trailing slash). Include http:// # IPS4_API_KEY - API key provided by IPS4 ##################################### -IPS4_URL = os.environ.get('AA_IPS4_URL', 'http://example.com/ips4') -IPS4_API_KEY = os.environ.get('AA_IPS4_API_KEY', '') +IPS4_URL = '' +IPS4_API_KEY = '' IPS4_DB = { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'alliance_ips4', - 'USER': os.environ.get('AA_DB_IPS4_USER', 'allianceserver-ips4'), - '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'), + 'USER': 'allianceserver-ips4', + 'PASSWORD': '', + 'HOST': '127.0.0.1', + 'PORT': '3306', } ##################################### # SEAT Configuration ##################################### -# SEAT_URL - base url of the seat install (no trailing slash) +# SEAT_URL - Base URL of the seat install (no trailing slash). Include http:// # SEAT_XTOKEN - API key X-Token provided by SeAT ##################################### -SEAT_URL = os.environ.get('AA_SEAT_URL', 'http://example.com/seat') -SEAT_XTOKEN = os.environ.get('AA_SEAT_XTOKEN', '') +SEAT_URL = '' +SEAT_XTOKEN = '' ###################################### # SMF Configuration ###################################### -SMF_URL = os.environ.get('AA_SMF_URL', 'https://example.com') +# SMF_URL - Web address of the forums. Include leading http:// +###################################### +SMF_URL = '' SMF_DB = { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'alliance_smf', - 'USER': os.environ.get('AA_DB_SMF_USER', 'allianceserver-smf'), - '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'), + 'USER': 'allianceserver-smf', + 'PASSWORD': '', + 'HOST': '127.0.0.1', + 'PORT': '3306', } ###################################### @@ -531,10 +443,10 @@ SMF_DB = { # FLEETUP_API_ID - The API id from http://fleet-up.com/Api/MyKeys # FLEETUP_GROUP_ID - The id of the group you want to pull data from, see http://fleet-up.com/Api/Endpoints#groups_mygroupmemberships ###################################### -FLEETUP_APP_KEY = os.environ.get('AA_FLEETUP_APP_KEY', '') -FLEETUP_USER_ID = os.environ.get('AA_FLEETUP_USER_ID', '') -FLEETUP_API_ID = os.environ.get('AA_FLEETUP_API_ID', '') -FLEETUP_GROUP_ID = os.environ.get('AA_FLEETUP_GROUP_ID', '') +FLEETUP_APP_KEY = '' +FLEETUP_USER_ID = '' +FLEETUP_API_ID = '' +FLEETUP_GROUP_ID = '' ##################################### # Logging Configuration @@ -659,11 +571,6 @@ if 'services.modules.market' in INSTALLED_APPS: if 'services.modules.ips4' in INSTALLED_APPS: DATABASES['ips4'] = IPS4_DB -# Ensure corp/alliance IDs are expected types -STR_CORP_IDS = [str(id) for id in CORP_IDS] -STR_ALLIANCE_IDS = [str(id) for id in ALLIANCE_IDS] -STR_BLUE_CORP_IDS = [str(id) for id in BLUE_CORP_IDS] -STR_BLUE_ALLIANCE_IDS = [str(id) for id in BLUE_ALLIANCE_IDS] # Conditionally add periodic tasks for services if installed if 'services.modules.teamspeak3' in INSTALLED_APPS: diff --git a/alliance_auth/tests/auth_utils.py b/alliance_auth/tests/auth_utils.py index 7bb6e3a6..7b5ca99e 100644 --- a/alliance_auth/tests/auth_utils.py +++ b/alliance_auth/tests/auth_utils.py @@ -1,15 +1,11 @@ from __future__ import unicode_literals from django.db.models.signals import m2m_changed, pre_save -from django.contrib.auth.models import User, Group, Permission - +from django.contrib.auth.models import User, Group from services.signals import m2m_changed_user_groups, pre_save_user from services.signals import m2m_changed_group_permissions, m2m_changed_user_permissions from authentication.signals import pre_save_auth_state - -from authentication.tasks import make_member, make_blue -from authentication.models import AuthServicesInfo -from authentication.states import MEMBER_STATE, BLUE_STATE, NONE_STATE +from authentication.models import UserProfile from eveonline.models import EveCharacter @@ -72,7 +68,7 @@ class AuthUtils: @classmethod def add_main_character(cls, user, name, character_id, corp_id='', corp_name='', corp_ticker='', alliance_id='', alliance_name=''): - EveCharacter.objects.create( + char = EveCharacter.objects.create( character_id=character_id, character_name=name, corporation_id=corp_id, @@ -83,7 +79,7 @@ class AuthUtils: api_id='1234', user=user ) - AuthServicesInfo.objects.update_or_create(user=user, defaults={'main_char_id': character_id}) + UserProfile.objects.update_or_create(user=user, defaults={'main_character': char}) @classmethod def add_permissions_to_groups(cls, perms, groups, disconnect_signals=True): diff --git a/alliance_auth/urls.py b/alliance_auth/urls.py index 5ccbc7dc..8961932d 100755 --- a/alliance_auth/urls.py +++ b/alliance_auth/urls.py @@ -3,9 +3,8 @@ 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 -import django.contrib.auth.views +import authentication.urls import authentication.views -import eveonline.views import services.views import groupmanagement.views import optimer.views @@ -19,16 +18,19 @@ import corputils.urls import esi.urls import permissions_tool.urls from alliance_auth import NAME +from alliance_auth.hooks import get_hooks admin.site.site_header = NAME -from alliance_auth.hooks import get_hooks # Functional/Untranslated URL's urlpatterns = [ # Locale url(r'^i18n/', include('django.conf.urls.i18n')), + # Authentication + url(r'', include(authentication.urls, namespace='authentication')), + # Admin urls url(r'^admin/', include(admin.site.urls)), @@ -36,17 +38,6 @@ urlpatterns = [ url(r'^sso/', include(esi.urls, namespace='esi')), url(r'^sso/login$', authentication.views.sso_login, name='auth_sso_login'), - # Index - url(_(r'^$'), authentication.views.index_view, name='auth_index'), - - # Authentication - url(r'^logout_user/', authentication.views.logout_user, name='auth_logout_user'), - - # Eve Online - url(r'^main_character_change/(\w+)/$', eveonline.views.main_character_change, - name='auth_main_character_change'), - url(r'^api_verify_owner/(\w+)/$', eveonline.views.api_sso_validate, name='auth_api_sso'), - # 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'), @@ -79,32 +70,6 @@ urlpatterns += i18n_patterns( 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/'), authentication.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/$'), eveonline.views.dashboard_view, name='auth_dashboard'), - url(_(r'^help/$'), authentication.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'^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'), - # Corputils url(_(r'^corpstats/'), include(corputils.urls, namespace='corputils')), diff --git a/authentication/admin.py b/authentication/admin.py index 999fb28d..65b6f793 100644 --- a/authentication/admin.py +++ b/authentication/admin.py @@ -5,39 +5,11 @@ from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.auth.models import User from django.utils.text import slugify from django import forms -from authentication.models import AuthServicesInfo, State, get_none_state -from eveonline.models import EveCharacter +from authentication.models import State, get_guest_state from alliance_auth.hooks import get_hooks from services.hooks import ServicesHook -@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 - - @staticmethod - def has_delete_permission(request, obj=None): - return False - - @staticmethod - def has_add_permission(request, obj=None): - return False - - search_fields = [ - 'user__username', - 'main_char_id', - ] - list_display = ('user', 'main_character') - - def make_service_hooks_update_groups_action(service): """ Make a admin action for the given service @@ -103,16 +75,16 @@ class StateForm(forms.ModelForm): def _is_none_state(self): instance = getattr(self, 'instance', None) if instance and instance.pk: - return instance == get_none_state() + return instance == get_guest_state() def __init__(self, *args, **kwargs): super(StateForm, self).__init__(*args, **kwargs) - if _is_none_state(): + if self._is_none_state(): self.fields['name'].widget.attrs['readonly'] = True def clean_name(self): if self._is_none_state(): - return instance.name + return self.instance.name return self.cleaned_data['name'] @@ -122,6 +94,6 @@ class StateAdmin(admin.ModelAdmin): @staticmethod def has_delete_permission(request, obj=None): - if obj == get_none_state(): + if obj == get_guest_state(): return False diff --git a/authentication/apps.py b/authentication/apps.py index 7fb56f6e..bd4c5ccf 100644 --- a/authentication/apps.py +++ b/authentication/apps.py @@ -1,10 +1,14 @@ from __future__ import unicode_literals from django.apps import AppConfig +from django.core.checks import register, Tags class AuthenticationConfig(AppConfig): name = 'authentication' def ready(self): + super(AuthenticationConfig, self).ready() import authentication.signals + from authentication import checks + register(Tags.security)(checks.check_login_scopes_setting) diff --git a/authentication/backends.py b/authentication/backends.py index 8666a31e..0fffd9e1 100644 --- a/authentication/backends.py +++ b/authentication/backends.py @@ -1,6 +1,7 @@ from django.contrib.auth.backends import ModelBackend from django.contrib.auth.models import Permission -from authentication.models import UserProfile +from authentication.models import UserProfile, CharacterOwnership +from django.contrib.auth.models import User class StateBackend(ModelBackend): @@ -10,7 +11,7 @@ class StateBackend(ModelBackend): user_state_query = 'state__%s__user' % profile_state_field.related_query_name() return Permission.objects.filter(**{user_state_query: user_obj}) - def get_state_permission(self, user_obj, obj=None): + def get_state_permissions(self, user_obj, obj=None): return self._get_permissions(user_obj, obj, 'state') def get_all_permissions(self, user_obj, obj=None): @@ -21,3 +22,49 @@ class StateBackend(ModelBackend): user_obj._perm_cache.update(self.get_group_permissions(user_obj)) user_obj._perm_cache.update(self.get_state_permissions(user_obj)) return user_obj._perm_cache + + def authenticate(self, token=None): + if not token: + return None + try: + ownership = CharacterOwnership.objects.get(character__character_id=token.character_id) + if ownership.owner_hash == token.character_owner_hash: + return ownership.user + else: + ownership.delete() + return self.create_user(token) + except CharacterOwnership.DoesNotExist: + try: + # insecure legacy main check for pre-sso registration auth installs + profile = UserProfile.objects.get(main_character__character_id=token.character_id) + # attach an ownership + CharacterOwnership.objects.create_by_token(token) + return profile.user + except UserProfile.DoesNotExist: + pass + return self.create_user(token) + + def create_user(self, token): + username = self.iterate_username(token.charater_name) # build unique username off character name + user = User.objects.create_user(username) + user.set_unusable_password() # prevent login via password + user.is_active = False # prevent login until email set + user.save() + token.user = user + co = CharacterOwnership.objects.create_by_token(token) # assign ownership to this user + user.profile.main_character = co.character # assign main character as token character + user.profile.save() + return user + + @staticmethod + def iterate_username(name): + if User.objects.filter(username__startswith=name).exists(): + u = User.objects.filter(username__startswith=name) + num = len(u) + username = "%s_%s" % (name, num) + while u.filter(username=username).exists(): + num += 1 + username = "%s_%s" % (name, num) + else: + username = name + return username diff --git a/authentication/checks.py b/authentication/checks.py new file mode 100644 index 00000000..7ebb2d92 --- /dev/null +++ b/authentication/checks.py @@ -0,0 +1,13 @@ +from __future__ import unicode_literals +from django.core.checks import Error +from django.conf import settings + + +def check_login_scopes_setting(*args, **kwargs): + errors = [] + try: + assert settings.LOGIN_TOKEN_SCOPES + except (AssertionError, AttributeError): + errors.append(Error('LOGIN_TOKEN_SCOPES setting cannot be blank.', + hint='SSO tokens used for logging in must require scopes to be refreshable.')) + return errors diff --git a/authentication/context_processors.py b/authentication/context_processors.py deleted file mode 100644 index 1f3084f9..00000000 --- a/authentication/context_processors.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import unicode_literals -from authentication.states import NONE_STATE, BLUE_STATE, MEMBER_STATE -from authentication.managers import UserState -from django.conf import settings - - -def membership_state(request): - return UserState.get_membership_state(request) - - -def states(request): - return { - 'BLUE_STATE': BLUE_STATE, - 'MEMBER_STATE': MEMBER_STATE, - 'NONE_STATE': NONE_STATE, - 'MEMBER_BLUE_STATE': [MEMBER_STATE, BLUE_STATE], - } diff --git a/authentication/decorators.py b/authentication/decorators.py deleted file mode 100644 index c08fc8cb..00000000 --- a/authentication/decorators.py +++ /dev/null @@ -1,23 +0,0 @@ -from __future__ import unicode_literals -from django.contrib.auth.decorators import user_passes_test -from authentication.managers import UserState - - -def _state_required(state_test, *args, **kwargs): - return user_passes_test(state_test, *args, **kwargs) - - -def members(*args, **kwargs): - return _state_required(UserState.member_state, *args, **kwargs) - - -def blues(*args, **kwargs): - return _state_required(UserState.blue_state, *args, **kwargs) - - -def members_and_blues(*args, **kwargs): - return _state_required(UserState.member_or_blue_state, *args, **kwargs) - - -def none_state(*args, **kwargs): - return _state_required(UserState.none_state, *args, **kwargs) diff --git a/authentication/forms.py b/authentication/forms.py index 76aa3771..124e6fd8 100644 --- a/authentication/forms.py +++ b/authentication/forms.py @@ -1,42 +1,7 @@ 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()) 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 + email = forms.EmailField(label=_('Email'), max_length=254, required=True) diff --git a/authentication/managers.py b/authentication/managers.py index 4bfa0a39..16c888c7 100755 --- a/authentication/managers.py +++ b/authentication/managers.py @@ -1,75 +1,57 @@ from __future__ import unicode_literals -from django.contrib.auth.models import User -from django.conf import settings -from authentication.states import NONE_STATE, BLUE_STATE, MEMBER_STATE -from authentication.models import AuthServicesInfo - +from django.db.models import Manager, QuerySet, Q +from eveonline.managers import EveManager +from eveonline.models import EveCharacter import logging logger = logging.getLogger(__name__) -class AuthServicesInfoManager: - def __init__(self): - pass +class CharacterOwnershipManager(Manager): + def create_by_token(self, token): + if not EveCharacter.objects.filter(character_id=token.character_id).exists(): + EveManager.create_character(token.character_id) + return self.create(character=EveCharacter.objects.get(characte_id=token.character_id), user=token.user, + owner_hash=token.character_owner_hash) - @staticmethod - 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 = AuthServicesInfo.objects.get(user=user) - 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)) + +class StateQuerySet(QuerySet): + def available_to_character(self, character): + query = Q(member_characters__character_id=character.character_id) + query |= Q(member_corporations__corporation_id=character.corporation_id) + query |= Q(member_alliances__alliance_id=character.alliance_id) + query |= Q(public=True) + return self.filter(query) + + def available_to_user(self, user): + if user.profile.main_character: + return self.available_to_character(user.profile.main_character) else: - logger.error("Failed to update user %s main character id to %s: user does not exist." % (user, char_id)) - - @staticmethod - 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 = AuthServicesInfo.objects.get(user=user) - 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)) + return self.none() -class UserState: - def __init__(self): - pass +class StateManager(Manager): + def get_queryset(self): + return StateQuerySet(self.model, using=self._db) - MEMBER_STATE = MEMBER_STATE - BLUE_STATE = BLUE_STATE - NONE_STATE = NONE_STATE + def available_to_character(self, character): + return self.get_queryset().available_to_character(character) - @classmethod - def member_state(cls, user): - return cls.state_required(user, [cls.MEMBER_STATE]) + def available_to_user(self, user): + return self.get_queryset().available_to_user(user) - @classmethod - def member_or_blue_state(cls, user): - return cls.state_required(user, [cls.MEMBER_STATE, cls.BLUE_STATE]) + def get_for_character(self, character): + states = self.get_queryset().available_to_character(character).order_by('priority') + if states.exists(): + return states[0] + else: + from authentication.models import get_guest_state + return get_guest_state() - @classmethod - def blue_state(cls, user): - return cls.state_required(user, [cls.BLUE_STATE]) - - @classmethod - def none_state(cls, user): - return cls.state_required(user, [cls.NONE_STATE]) - - @classmethod - def get_membership_state(cls, request): - if request.user.is_authenticated: - auth = AuthServicesInfo.objects.get(user=request.user) - return {'STATE': auth.state} - return {'STATE': cls.NONE_STATE} - - @staticmethod - def state_required(user, states): - if user.is_superuser and settings.SUPERUSER_STATE_BYPASS: - return True - if user.is_authenticated: - auth = AuthServicesInfo.objects.get(user=user) - return auth.state in states - return False + def get_for_user(self, user): + states = self.get_queryset().available_to_user(user) + if states.exists(): + return states[0] + else: + from authentication.models import get_guest_state + return get_guest_state() \ No newline at end of file diff --git a/authentication/migrations/0008_set_state.py b/authentication/migrations/0008_set_state.py index 7fffd92a..8951bcba 100644 --- a/authentication/migrations/0008_set_state.py +++ b/authentication/migrations/0008_set_state.py @@ -4,52 +4,6 @@ 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 str(char.corporation_id) in settings.STR_CORP_IDS: - return MEMBER_STATE - elif str(char.alliance_id) in settings.STR_ALLIANCE_IDS: - 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 = AuthServicesInfo.objects.get(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(user=user) - 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): @@ -60,5 +14,4 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RunPython(set_initial_state, migrations.RunPython.noop) ] diff --git a/authentication/migrations/0014_fleetup_permission.py b/authentication/migrations/0014_fleetup_permission.py new file mode 100644 index 00000000..48f1aee1 --- /dev/null +++ b/authentication/migrations/0014_fleetup_permission.py @@ -0,0 +1,24 @@ +# -*- 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_permission(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="view_fleetup", content_type=ct, name="view_fleetup") + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0013_service_modules'), + ] + + operations = [ + migrations.RunPython(create_permission, migrations.RunPython.noop) + ] diff --git a/authentication/migrations/0015_user_profiles.py b/authentication/migrations/0015_user_profiles.py new file mode 100644 index 00000000..9609c25b --- /dev/null +++ b/authentication/migrations/0015_user_profiles.py @@ -0,0 +1,227 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-03-22 23:09 +from __future__ import unicode_literals + +import authentication.models +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +def create_guest_state(apps, schema_editor): + State = apps.get_model('authentication', 'State') + State.objects.update_or_create(name='Guest', defaults={'priority': 0, 'public': True}) + + +def create_member_state(apps, schema_editor): + Group = apps.get_model('auth', 'Group') + State = apps.get_model('authentication', 'State') + EveAllianceInfo = apps.get_model('eveonline', 'EveAllianceInfo') + EveCorporationInfo = apps.get_model('eveonline', 'EveCorporationInfo') + + member_state_name = getattr(settings, 'DEFAULT_AUTH_GROUP', 'Member') + s = State.objects.update_or_create(name=member_state_name, defaults={'priority': 100, 'public': False})[0] + try: + # move group permissions to state + g = Group.objects.get(name=member_state_name) + s.permissions.add(g.permissions.all()) + g.delete() + except Group.DoesNotExist: + pass + + # auto-populate member IDs + CORP_IDS = getattr(settings, 'CORP_IDS', []) + ALLIANCE_IDS = getattr(settings, 'ALLIANCE_IDS', []) + s.member_corporations.add(EveCorporationInfo.objects.filter(corporation_id__in=CORP_IDS)) + s.member_alliances.add(EveAllianceInfo.objects.filter(alliance_id__in=ALLIANCE_IDS)) + + +def create_member_group(apps, schema_editor): + Group = apps.get_model('auth', 'Group') + State = apps.get_model('authentication', 'State') + member_state_name = getattr(settings, 'DEFAULT_AUTH_GROUP', 'Member') + + g = Group.objects.get_or_create(name=member_state_name)[0] + try: + # move permissions back + state = State.objects.get(name=member_state_name) + g.permissions.add(state.permissions.all()) + + # move users back + for profile in state.userprofile_set.all().select_related('user'): + profile.user.groups.add(g) + except State.DoesNotExist: + pass + + +def create_blue_state(apps, schema_editor): + Group = apps.get_model('auth', 'Group') + State = apps.get_model('authentication', 'State') + EveAllianceInfo = apps.get_model('eveonline', 'EveAllianceInfo') + EveCorporationInfo = apps.get_model('eveonline', 'EveCorporationInfo') + blue_state_name = getattr(settings, 'DEFAULT_BLUE_GROUP', 'Blue') + + s = State.objects.update_or_create(name=blue_state_name, defaults={'priority': 50, 'public': False})[0] + try: + # move group permissions to state + g = Group.objects.get(name=blue_state_name) + s.permissions.add(g.permissions.all()) + g.permissions.clear() + except Group.DoesNotExist: + pass + + # auto-populate blue member IDs + BLUE_CORP_IDS = getattr(settings, 'BLUE_CORP_IDS', []) + BLUE_ALLIANCE_IDS = getattr(settings, 'BLUE_ALLIANCE_IDS', []) + s.member_corporations.add(EveCorporationInfo.objects.filter(corporation_id__in=BLUE_CORP_IDS)) + s.member_alliances.add(EveAllianceInfo.objects.filter(alliance_id__in=BLUE_ALLIANCE_IDS)) + + +def create_blue_group(apps, schema_editor): + Group = apps.get_model('auth', 'Group') + State = apps.get_model('authentication', 'State') + blue_state_name = getattr(settings, 'DEFAULT_BLUE_GROUP', 'Blue') + + g = Group.objects.get_or_create(name=blue_state_name)[0] + try: + # move permissions back + state = State.objects.get(name=blue_state_name) + g.permissions.add(state.permissions.all()) + + # move users back + for profile in state.userprofile_set.all().select_related('user'): + profile.user.groups.add(g) + except State.DoesNotExist: + pass + + +def populate_ownerships(apps, schema_editor): + Token = apps.get_model('esi', 'Token') + CharacterOwnership = apps.get_model('authentication', 'CharacterOwnership') + EveCharacter = apps.get_model('eveonline', 'EveCharacter') + + unique_character_owners = [t['character_id'] for t in + Token.objects.all().values('character_id').annotate(n=models.Count('user')) if + t['n'] == 1 and EveCharacter.objects.filter(character_id=t['character_id'].exists())] + + tokens = Token.objects.filter(character_id__in=unique_character_owners) + for c_id in unique_character_owners: + ts = tokens.filter(character_id=c_id).order_by('created') + for t in ts: + if t.can_refresh: + # find newest refreshable token and use it as basis for CharacterOwnership + CharacterOwnership.objecs.create_by_token(t) + break + + +def create_profiles(apps, schema_editor): + AuthServicesInfo = apps.get_model('authentication', 'AuthServicesInfo') + State = apps.get_model('authentication', 'State') + UserProfile = apps.get_model('authentication', 'UserProfile') + EveCharacter = apps.get_model('eveonline', 'EveCharacter') + + # grab AuthServicesInfo if they have a unique main_char_id and the EveCharacter exists + unique_mains = [auth['main_char_id'] for auth in + AuthServicesInfo.objects.exclude(main_char_id='').values('main_char_id').annotate( + n=models.Count('main_char_id')) if + auth['n'] == 1 and EveCharacter.objects.filter(character_id=auth['main_char_id'].exists())] + + auths = AuthServicesInfo.objects.filter(main_char_id__in=unique_mains).select_related('user') + for auth in auths: + # carry states and mains forward + profile = UserProfile.objects.get_or_create(user=auth.user.pk) + state = State.objects.get(name=auth.state if auth.state else 'Guest') + profile.state = state + char = EveCharacter.objects.get(character_id=auth.main_char_id) + profile.main_character = char + profile.save() + + +def recreate_authservicesinfo(apps, schema_editor): + AuthServicesInfo = apps.get_model('authentication', 'AuthServicesInfo') + UserProfile = apps.get_model('authentication', 'UserProfile') + User = apps.get_model('auth', 'User') + + # recreate all missing AuthServicesInfo models + AuthServicesInfo.objects.bulk_create([AuthServicesInfo(user=u.pk) for u in User.objects.all()]) + + # repopulate main characters + for profile in UserProfile.objects.exclude(main_character__isnull=True).select_related('user', 'main_character'): + AuthServicesInfo.objects.update_or_create(user=profile.user, defaults={'main_char_id': profile.main_character.character_id}) + + # repopulate states we understand + for profile in UserProfile.objects.exclude(state__name='Guest').filter(state__name__in=['Member', 'Blue']).select_related('user', 'state'): + AuthServicesInfo.objects.update_or_create(user=profile.user, defaults={'state': profile.state.name}) + + +class Migration(migrations.Migration): + dependencies = [ + ('auth', '0008_alter_user_username_max_length'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('eveonline', '0008_remove_apikeys'), + ('authentication', '0014_fleetup_permission'), + ('esi', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='CharacterOwnership', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('owner_hash', models.CharField(max_length=28, unique=True)), + ('character', + models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='character_ownership', + to='eveonline.EveCharacter')), + ('user', + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='character_ownerships', + to=settings.AUTH_USER_MODEL)), + ], + options={ + 'default_permissions': ('change', 'delete'), + }, + ), + migrations.CreateModel( + name='State', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=20, unique=True)), + ('priority', models.IntegerField(unique=True)), + ('public', models.BooleanField(default=False)), + ('member_alliances', models.ManyToManyField(to='eveonline.EveAllianceInfo')), + ('member_characters', models.ManyToManyField(to='eveonline.EveCharacter')), + ('member_corporations', models.ManyToManyField(to='eveonline.EveCorporationInfo')), + ('permissions', models.ManyToManyField(blank=True, to='auth.Permission')), + ], + options={ + 'ordering': ['priority'], + }, + ), + migrations.CreateModel( + name='UserProfile', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('main_character', + models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, + to='eveonline.EveCharacter')), + ('state', models.ForeignKey(on_delete=models.SET(authentication.models.get_guest_state), + to='authentication.State')), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', + to=settings.AUTH_USER_MODEL)), + ], + options={ + 'default_permissions': ('change',), + }, + ), + migrations.RunPython(create_guest_state, migrations.RunPython.noop), + migrations.RunPython(create_member_state, create_member_group), + migrations.RunPython(create_blue_state, create_blue_group), + migrations.RunPython(populate_ownerships, migrations.RunPython.noop), + migrations.RunPython(create_profiles, recreate_authservicesinfo), + migrations.RemoveField( + model_name='authservicesinfo', + name='user', + ), + migrations.DeleteModel( + name='AuthServicesInfo', + ), + ] diff --git a/authentication/models.py b/authentication/models.py index d5366466..d5d904c6 100755 --- a/authentication/models.py +++ b/authentication/models.py @@ -1,40 +1,24 @@ 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 -from eveonline.models import EveCharacter - - -@python_2_unicode_compatible -class AuthServicesInfo(models.Model): - class Meta: - default_permissions = ('change',) - - STATE_CHOICES = ( - (NONE_STATE, 'None'), - (BLUE_STATE, 'Blue'), - (MEMBER_STATE, 'Member'), - ) - - main_char_id = models.CharField(max_length=64, blank=True, default="") - user = models.OneToOneField(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' +from django.contrib.auth.models import User, Permission +from authentication.managers import CharacterOwnershipManager, StateManager +from eveonline.models import EveCharacter, EveCorporationInfo, EveAllianceInfo @python_2_unicode_compatible class State(models.Model): - name = models.CharField(_('name'), max_length=20, unique=True) - permissions = models.ManyToManyField( - Permission, - verbose_name=_('permissions'), - blank=True, - ) + name = models.CharField(max_length=20, unique=True) + permissions = models.ManyToManyField(Permission, blank=True) priority = models.IntegerField(unique=True) + member_characters = models.ManyToManyField(EveCharacter) + member_corporations = models.ManyToManyField(EveCorporationInfo) + member_alliances = models.ManyToManyField(EveAllianceInfo) + public = models.BooleanField(default=False) + + objects = StateManager() + class Meta: ordering = ['priority'] @@ -42,8 +26,8 @@ class State(models.Model): return self.name -def get_none_state(): - return State.objects.get_or_create(name='None')[0] +def get_guest_state(): + return State.objects.update_or_create(name='Guest', defaults={'priority': 0, 'public': True})[0] @python_2_unicode_compatible @@ -52,7 +36,28 @@ class UserProfile(models.Model): default_permissions = ('change',) user = models.OneToOneField(User, related_name='profile', on_delete=models.CASCADE) - main_character = models.ForeignKey(EveCharacter, on_delete=models.CASCADE) - state = models.ForeignKey(State, on_delete=models.SET(get_none_state)) + main_character = models.OneToOneField(EveCharacter, blank=True, null=True, on_delete=models.SET_NULL) + state = models.ForeignKey(State, on_delete=models.SET(get_guest_state)) + + def assign_state(self, commit=True): + self.state = State.objects.get_for_user(self.user) + if commit: + self.save(update_fields=['state']) + + def __str__(self): + return "%s Profile" % self.user + + +@python_2_unicode_compatible +class CharacterOwnership(models.Model): + class Meta: + default_permissions = ('change', 'delete') + + character = models.OneToOneField(EveCharacter, on_delete=models.CASCADE, related_name='character_ownership') owner_hash = models.CharField(max_length=28, unique=True) - owner_token = models.ForeignKey(Token, on_delete=models.SET_NULL) + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='character_ownerships') + + objects = CharacterOwnershipManager() + + def __str__(self): + return "%s: %s" % (self.user, self.character) diff --git a/authentication/signals.py b/authentication/signals.py index 1d7025b8..10f9163d 100644 --- a/authentication/signals.py +++ b/authentication/signals.py @@ -1,34 +1,70 @@ from __future__ import unicode_literals -from django.db.models.signals import pre_save, post_save +from django.db.models.signals import post_save, pre_delete from django.dispatch import receiver from django.contrib.auth.models import User -from authentication.models import AuthServicesInfo -from authentication.states import MEMBER_STATE, BLUE_STATE -from authentication.tasks import make_member, make_blue, disable_member +from authentication.models import CharacterOwnership, UserProfile, get_guest_state from services.tasks import validate_services +from esi.models import Token +from eveonline.managers import EveManager +from eveonline.models import EveCharacter 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.apply(args=(instance.user,)) +# Is there a smarter way to intercept pre_save with a diff main_character or state? +@receiver(post_save, sender=UserProfile) +def reassess_on_profile_save(sender, instance, created, *args, **kwargs): + # catches post_save from profiles to trigger necessary service and state checks + if not created: + update_fields = kwargs.pop('update_fields', []) + if 'state' not in update_fields: + instance.assign_state() + # TODO: how do we prevent running this twice on profile state change? + validate_services(instance.user) @receiver(post_save, sender=User) -def post_save_user(sender, instance, created, *args, **kwargs): +def create_required_models(sender, instance, created, *args, **kwargs): # ensure all users have a model if created: - AuthServicesInfo.objects.get_or_create(user=instance) + UserProfile.objects.get_or_create(user=instance) + +@receiver(post_save, sender=Token) +def record_character_ownership(sender, instance, created, *args, **kwargs): + if created: + # purge ownership records if the hash or auth user account has changed + CharacterOwnership.objects.filter(character__character_id=instance.character_id).exclude( + owner_hash=instance.owner_hash).exclude(user=instance.user).delete() + # create character if needed + if EveCharacter.objects.filter(character_id=instance.character_id).exists() is False: + EveManager.create_character(instance.character_id) + char = EveCharacter.objects.get(character_id=instance.character_id) + CharacterOwnership.objects.update_or_create(character=char, + defaults={'owner_hash': instance.owner_hash, 'user': instance.user}) + + +@receiver(pre_delete, sender=CharacterOwnership) +def validate_main_character(sender, instance, *args, **kwargs): + if instance.user.profile.main_character == instance.character: + # clear main character as user no longer owns them + instance.user.profile.main_character = None + instance.user.profile.save() + + +@receiver(pre_delete, sender=Token) +def validate_main_character_token(sender, instance, *args, **kwargs): + if UserProfile.objects.filter(main_character__character_id=instance.character_id): + if not Token.objects.filter(character_id=instance.character_id).filter(user=instance.user).exists(): + # clear main character as we can no longer verify ownership + instance.user.profile.main_character = None + instance.user.profile.save() + + +@receiver(post_save, sender=User) +def assign_state_on_reactivate(sender, instance, *args, **kwargs): + # There's no easy way to trigger an action upon saving from pre_save signal + # If we're saving a user and that user is in the Guest state, assume is_active was just set to True and assign state + if instance.is_active and instance.profile.state == get_guest_state(): + instance.profile.assign_state() diff --git a/authentication/states.py b/authentication/states.py deleted file mode 100644 index 48c76952..00000000 --- a/authentication/states.py +++ /dev/null @@ -1,4 +0,0 @@ -from __future__ import unicode_literals -MEMBER_STATE = 'Member' -BLUE_STATE = 'Blue' -NONE_STATE = None diff --git a/authentication/tasks.py b/authentication/tasks.py deleted file mode 100644 index 2810f782..00000000 --- a/authentication/tasks.py +++ /dev/null @@ -1,189 +0,0 @@ -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): - """ - Disable a member who is transitioning to a NONE state. - :param user: django.contrib.auth.models.User to disable - :return: - """ - 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 all non-public user %s groups to disable member." % user) - user.groups.remove(*user.groups.filter(authgroup__public=False)) - validate_services.apply(args=(user,)) - - -def disable_user(user): - """ - Disable a user who is being set inactive or deleted - :param user: django.contrib.auth.models.User to disable - :return: - """ - logger.debug("Disabling user %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.apply(args=(user,)) - - -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 str(char.corporation_id) in settings.STR_CORP_IDS: - logger.debug("Character %s in member corp id %s" % (char, char.corporation_id)) - return MEMBER_STATE - elif str(char.alliance_id) in settings.STR_ALLIANCE_IDS: - logger.debug("Character %s in member alliance id %s" % (char, char.alliance_id)) - return MEMBER_STATE - elif not EveCorporationInfo.objects.filter(corporation_id=char.corporation_id).exists(): - 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 = AuthServicesInfo.objects.get(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(user=user) - if auth.state != state: - auth.state = state - auth.save() - notify(user, "Membership State Change", message="You membership state has been changed to %s" % state) - assign_corp_group(auth) - assign_alliance_group(auth) - - -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/templates/authentication/dashboard.html b/authentication/templates/authentication/dashboard.html new file mode 100644 index 00000000..1f291f2e --- /dev/null +++ b/authentication/templates/authentication/dashboard.html @@ -0,0 +1,94 @@ +{% extends "registered/base.html" %} +{% load staticfiles %} +{% load i18n %} + +{% block title %}{% trans "Dashboard" %}{% endblock %} + +{% block content %} +
+

{% trans "Dashboard" %}

+
+
+
+
+
{% trans "Main Character" %}
+
+ {% if request.user.profile.main_character %} + {% with request.user.profile.main_character as main %} +
+ + + +
{{ main.character_name }}
+
+
+ + + +
{{ main.corporation_name }}
+
+
+ {% if main.alliance_id %} + + + +
{{ main.alliance_name }}
+ {% endif %} +
+ {% endwith %} + {% else %} + + {% endif %} +
+ + +
+
+
+
+
+
+
{% trans "Groups" %}
+
+
+ + {% for group in user.groups.all %} + + + + {% endfor %} +
{{ group.name }}
+
+
+
+
+
+
+
+
{% trans 'Characters' %}
+
+ + + + + + + + {% for ownership in request.user.character_ownerships.all %} + {% with ownership.character as char %} + + + + + + {% endwith %} + {% endfor %} +
{% trans 'Name' %}{% trans 'Corp' %}{% trans 'Alliance' %}
{{ char.character_name }}{{ char.corporation_name }}{{ char.alliance_name }}
+
+
+
+{% endblock %} diff --git a/authentication/templates/public/base.html b/authentication/templates/public/base.html new file mode 100644 index 00000000..95e0525e --- /dev/null +++ b/authentication/templates/public/base.html @@ -0,0 +1,49 @@ + + + + + + + + + {% block title %}{{ SITE_NAME }}{% endblock %} + + {% include 'bundles/bootstrap-css.html' %} + {% include 'bundles/fontawesome.html' %} + {% block extra_include %} + {% endblock %} + + + + +
+ {% block content %} + {% endblock %} +
+ + \ No newline at end of file diff --git a/authentication/templates/public/lang_select.html b/authentication/templates/public/lang_select.html new file mode 100644 index 00000000..13d5ecfd --- /dev/null +++ b/authentication/templates/public/lang_select.html @@ -0,0 +1,15 @@ +{% load i18n %} + \ No newline at end of file diff --git a/authentication/templates/public/login.html b/authentication/templates/public/login.html new file mode 100644 index 00000000..e110d580 --- /dev/null +++ b/authentication/templates/public/login.html @@ -0,0 +1,27 @@ +{% extends 'public/base.html' %} +{% block title %}Login{% endblock %} +{% block content %} +
+ {% if messages %} + {% for message in messages %} +
{{ message }}
+ {% endfor %} + {% endif %} +
+
+
+

+ + + +

+
+
+
+ {% include 'public/lang_select.html' %} +
+{% endblock %} +{% block extra_include %} + {% include 'bundles/bootstrap-js.html' %} +{% endblock %} + diff --git a/authentication/templates/public/register.html b/authentication/templates/public/register.html new file mode 100644 index 00000000..1c8846e9 --- /dev/null +++ b/authentication/templates/public/register.html @@ -0,0 +1,24 @@ +{% load staticfiles %} +{% load bootstrap %} +{% load i18n %} +{% extends 'public/base.html' %} +{% block title %}Registration{% endblock %} +{% block extra_include %} + {% include 'bundles/bootstrap-css.html' %} + {% include 'bundles/fontawesome.html' %} + {% include 'bundles/bootstrap-js.html' %} +{% endblock %} +{% block content %} +
+
+
+
+ {% csrf_token %} + {{ form|bootstrap }} + +
+
+
+ {% include 'public/lang_select.html' %} +
+{% endblock %} diff --git a/stock/templates/public/base.html b/authentication/templates/registered/base.html old mode 100755 new mode 100644 similarity index 76% rename from stock/templates/public/base.html rename to authentication/templates/registered/base.html index 51a66054..a5acd44d --- a/stock/templates/public/base.html +++ b/authentication/templates/registered/base.html @@ -104,20 +104,19 @@
  • {% trans "Aux Navigation" %}
  • +
  • {% trans " Services" %}
  • - {% if not STATE == MEMBER_STATE or perms.auth.human_resources %} -
  • - - {% trans " Applications" %} - -
  • - {% endif %} +
  • + + {% trans " Applications" %} + +
  • {% if perms.corputils.view_corp_corpstats or perms.corputils.view_alliance_corpstats or perms.corputils.view_blue_corpstats %}
  • @@ -135,54 +134,47 @@
  • {% endif %} - {% if STATE in MEMBER_BLUE_STATE or user.is_superuser %} + {% if perms.auth.view_fleetup %}
  • Fleet-Up
  • + {% endif %} - {% endif %} - - {% if STATE in MEMBER_BLUE_STATE or user.is_superuser %} - {% if perms.auth.optimer_view %} + {% if perms.auth.optimer_view %}
  • {% trans " Fleet Operations" %}
  • - {% endif %} - {% if perms.auth.timer_view %} -
  • - - {% trans " Structure Timers" %} - -
  • - {% endif %} + {% endif %} + {% if perms.auth.timer_view %}
  • - - {% trans " Fleet Activity Tracking" %} - -
  • - -
  • - - {% trans " Ship Replacement" %} + + {% trans " Structure Timers" %}
  • {% endif %} + +
  • + + {% trans " Fleet Activity Tracking" %} + +
  • + +
  • + + {% trans " Ship Replacement" %} + +
  • {% menu_aux %}
  • {% trans "Util" %}
  • -
  • - - {% trans "Change Password" %} - -
  • - {% if STATE in MEMBER_BLUE_STATE or user.is_superuser %} + {% if perms.auth.jabber_broadcast or perms.auth.jabber_broadcast_all or user.is_superuser %}
  • {% trans " Fleet Broadcast Formatter" %} diff --git a/stock/templates/registration/password_change_done.html b/authentication/templates/registration/password_change_done.html similarity index 93% rename from stock/templates/registration/password_change_done.html rename to authentication/templates/registration/password_change_done.html index 68b6b6ac..4751680d 100644 --- a/stock/templates/registration/password_change_done.html +++ b/authentication/templates/registration/password_change_done.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load i18n static %} diff --git a/stock/templates/registration/password_change_form.html b/authentication/templates/registration/password_change_form.html similarity index 95% rename from stock/templates/registration/password_change_form.html rename to authentication/templates/registration/password_change_form.html index af7b857c..94125ea6 100644 --- a/stock/templates/registration/password_change_form.html +++ b/authentication/templates/registration/password_change_form.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load i18n static %} diff --git a/stock/templates/registration/password_reset_base.html b/authentication/templates/registration/password_reset_base.html similarity index 100% rename from stock/templates/registration/password_reset_base.html rename to authentication/templates/registration/password_reset_base.html diff --git a/stock/templates/registration/password_reset_complete.html b/authentication/templates/registration/password_reset_complete.html similarity index 100% rename from stock/templates/registration/password_reset_complete.html rename to authentication/templates/registration/password_reset_complete.html diff --git a/stock/templates/registration/password_reset_confirm.html b/authentication/templates/registration/password_reset_confirm.html similarity index 100% rename from stock/templates/registration/password_reset_confirm.html rename to authentication/templates/registration/password_reset_confirm.html diff --git a/stock/templates/registration/password_reset_done.html b/authentication/templates/registration/password_reset_done.html similarity index 100% rename from stock/templates/registration/password_reset_done.html rename to authentication/templates/registration/password_reset_done.html diff --git a/stock/templates/registration/password_reset_email.html b/authentication/templates/registration/password_reset_email.html similarity index 100% rename from stock/templates/registration/password_reset_email.html rename to authentication/templates/registration/password_reset_email.html diff --git a/stock/templates/registration/password_reset_form.html b/authentication/templates/registration/password_reset_form.html similarity index 100% rename from stock/templates/registration/password_reset_form.html rename to authentication/templates/registration/password_reset_form.html diff --git a/authentication/tests/test_tasks.py b/authentication/tests/test_tasks.py deleted file mode 100644 index 3d052a7c..00000000 --- a/authentication/tests/test_tasks.py +++ /dev/null @@ -1,84 +0,0 @@ -from __future__ import unicode_literals - -try: - # Py3 - from unittest import mock -except ImportError: - # Py2 - import mock - -from django.test import TestCase -from django.contrib.auth.models import Group, Permission - -from alliance_auth.tests.auth_utils import AuthUtils - -from authentication.tasks import disable_member, disable_user - - -class AuthenticationTasksTestCase(TestCase): - def setUp(self): - self.member = AuthUtils.create_member('auth_member') - self.none_user = AuthUtils.create_user('none_user', disconnect_signals=True) - - @mock.patch('services.signals.transaction') - def test_disable_member(self, transaction): - # Inert signals action - transaction.on_commit.side_effect = lambda fn: fn() - - # Add permission - perm = Permission.objects.create(codename='test_perm', name='test perm', content_type_id=1) - - # Add public group - pub_group = Group.objects.create(name="A Public group") - pub_group.authgroup.internal = False - pub_group.authgroup.public = True - pub_group.save() - - # Setup member - self.member.user_permissions.add(perm) - self.member.groups.add(pub_group) - - # Pre assertion - self.assertIn(pub_group, self.member.groups.all()) - self.assertGreater(len(self.member.groups.all()), 1) - - # Act - disable_member(self.member) - - # Assert - self.assertIn(pub_group, self.member.groups.all()) - # Everything but the single public group wiped - self.assertEqual(len(self.member.groups.all()), 1) - # All permissions wiped - self.assertEqual(len(self.member.user_permissions.all()), 0) - - @mock.patch('services.signals.transaction') - def test_disable_user(self, transaction): - # Inert signals action - transaction.on_commit.side_effect = lambda fn: fn() - - # Add permission - perm = Permission.objects.create(codename='test_perm', name='test perm', content_type_id=1) - - # Add public group - pub_group = Group.objects.create(name="A Public group") - pub_group.authgroup.internal = False - pub_group.authgroup.public = True - pub_group.save() - - # Setup member - self.member.user_permissions.add(perm) - self.member.groups.add(pub_group) - - # Pre assertion - self.assertIn(pub_group, self.member.groups.all()) - self.assertGreater(len(self.member.groups.all()), 1) - - # Act - disable_user(self.member) - - # Assert - # All groups wiped - self.assertEqual(len(self.member.groups.all()), 0) - # All permissions wiped - self.assertEqual(len(self.member.user_permissions.all()), 0) diff --git a/authentication/urls.py b/authentication/urls.py new file mode 100644 index 00000000..3a92b81e --- /dev/null +++ b/authentication/urls.py @@ -0,0 +1,21 @@ +from django.conf.urls import url, include +from django.contrib.auth.decorators import login_required +from django.views.generic.base import TemplateView +from authentication import views +from registration.backends.hmac import urls + +# inject our custom view classes into the HMAC scheme but use their urlpatterns because :efficiency: +urls.views = views + +app_name = 'authentication' + +urlpatterns = [ + url(r'^$', TemplateView.as_view(template_name='public/login.html'), name='login'), + url(r'^account/login/$', TemplateView.as_view(template_name='public/login.html')), + url(r'^account/characters/main/$', views.main_character_change, name='change_main_character'), + url(r'^account/characters/add/$', views.add_character, name='add_character'), + url(r'^account/', include(urls, namespace='registration')), + url(r'^help/$', login_required(TemplateView.as_view(template_name='public/help.html')), name='help'), + url(r'^dashboard/$', + login_required(TemplateView.as_view(template_name='authentication/dashboard.html')), name='dashboard'), +] diff --git a/authentication/views.py b/authentication/views.py index 14e237d7..ed2c1466 100644 --- a/authentication/views.py +++ b/authentication/views.py @@ -1,116 +1,123 @@ 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.shortcuts import render, redirect +from django.contrib.auth import login, authenticate +from django.shortcuts import redirect from django.contrib.auth.decorators import login_required from django.utils.translation import ugettext_lazy as _ -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 authentication.forms import RegistrationForm +from authentication.models import CharacterOwnership from django.contrib import messages +from django.contrib.auth.models import User +from django.conf import settings +from django.core import signing from esi.decorators import token_required +from registration.backends.hmac.views import RegistrationView as BaseRegistrationView, \ + ActivationView as BaseActivationView, REGISTRATION_SALT +from registration.signals import user_registered import logging logger = logging.getLogger(__name__) -def login_user(request): - logger.debug("login_user called by user %s" % request.user) - if request.method == 'POST': - form = LoginForm(request.POST) - logger.debug("Request of type POST, received form, valid: %s" % form.is_valid()) - if form.is_valid(): - user = authenticate(username=form.cleaned_data['username'], password=form.cleaned_data['password']) - logger.debug("Authentication attempt with supplied credentials. Received user %s" % user) - if user is not None: - if user.is_active: - logger.info("Successful login attempt from user %s" % user) - login(request, user) - redirect_to = request.POST.get('next', request.GET.get('next', '')) - if not redirect_to: - redirect_to = 'auth_dashboard' - return redirect(redirect_to) - 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']) - 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(request, 'public/login.html', context={'form': form}) - - -def logout_user(request): - logger.debug("logout_user called by user %s" % request.user) - temp_user = request.user - logout(request) - 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) - login(request, 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 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, token): +@token_required(scopes=settings.LOGIN_TOKEN_SCOPES) +def main_character_change(request, token): + logger.debug("main_character_change called by user %s for character %s" % (request.user, token.character_name)) try: - char = EveCharacter.objects.get(character_id=token.character_id) - if char.user: - if char.user.is_active: - login(request, char.user) - token.user = char.user - token.save() - return redirect('auth_dashboard') - 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) + co = CharacterOwnership.objects.get(character__character_id=token.character_id) + except CharacterOwnership.DoesNotExist: + co = CharacterOwnership.objects.create_by_token(token) + request.user.profile.main_character = co.character + request.user.profile.save(update_fields=['main_character']) + messages.success(request, _('Changed main character to %(char)s') % {"char": co.character}) + return redirect("auth_dashboard") + + +@token_required(new=True, scopes=settings.LOGIN_TOKEN_SCOPES) +def add_character(request, token): + if CharacterOwnership.objects.filter(character__character_id=token.character_id).filter( + owner_hash=token.character_owner_hash).filter(user=request.user).exists(): + messages.success(request, _('Added %(name)s to your account.'% ({'name': token.character_name}))) + else: + messages.error(request, _('Failed to add %(name)s to your account.' % ({'name': token.charater_name}))) + return redirect('authentication:dashboard') + + +""" +Override the HMAC two-step registration view to accommodate the three-step registration required. +Step 1: OAuth token to create user and profile. +Step 2: Get email and send activation link (but do not save email). +Step 3: Get link, save email and activate. + +Step 1 is necessary to automatically assign character ownership and a main character, both of which require a saved User +model - this means the ensuing registration form cannot create the user because it already exists. + +Email is not saved to the user model in Step 2 as a way of differentiating users who have not yet completed registration +(is_active=False) and users who have been disabled by an admin (is_active=False, email present). + +Because of this, the email address needs to be assigned in Step 3 after clicking the link, which means the link must +have the email address embedded much like the username. Key creation and decoding is overridden to support this action. +""" + + +# Step 1 +@token_required(new=True, scopes=settings.LOGIN_TOKEN_SCOPES) +def sso_login(request, token): + user = authenticate(token=token) + if user and user.is_active: + login(request, user) + return redirect(request.POST.get('next', request.GET.get('next', 'auth_dashboard'))) + elif user and not user.email: + # Store the new user PK in the session to enable us to identify the registering user in Step 2 + request.session['registration_uid'] = user.pk + # Go to Step 2 + return redirect('authentication:register') + else: + messages.error(request, _('Unable to authenticate as the selected character.')) + return redirect(settings.LOGIN_URL) + + +# Step 2 +class RegistrationView(BaseRegistrationView): + form_class = RegistrationForm + success_url = 'authentication:dashboard' + + def dispatch(self, *args, **kwargs): + # We're storing a key in the session to pass user information from OAuth response. Make sure it's there. + if not self.request.session.get('registration_uid', None) or not User.objects.filter( + pk=self.request.session.get('registration_uid')).exists(): + messages.error(self.request, _('Registration token has expired.')) + return redirect(settings.LOGIN_URL) + return super(RegistrationView, self).dispatch(*args, **kwargs) + + def register(self, form): + user = User.objects.get(pk=self.request.session.get('registration_uid')) + user.email = form.cleaned_data['email'] + user_registered.send(self.__class__, user=user, request=self.request) + # Go to Step 3 + self.send_activation_email(user) + return user + + def get_activation_key(self, user): + return signing.dumps(obj=[getattr(user, User.USERNAME_FIELD), user.email], salt=REGISTRATION_SALT) + + +# Step 3 +class ActivationView(BaseActivationView): + def validate_key(self, activation_key): + try: + dump = signing.loads(activation_key, salt=REGISTRATION_SALT, + max_age=settings.ACCOUNT_ACTIVATION_DAYS * 86400) + return dump + except signing.BadSignature: + return None + + def activate(self, *args, **kwargs): + dump = self.validate_key(kwargs.get('activation_key')) + if dump: + user = self.get_user(dump[0]) + if user: + user.email = dump[1] + user.is_active = True + user.save() + return user + return False diff --git a/corputils/managers.py b/corputils/managers.py index 86e984d9..1508674c 100644 --- a/corputils/managers.py +++ b/corputils/managers.py @@ -1,6 +1,4 @@ from django.db import models -from authentication.models import AuthServicesInfo -from eveonline.models import EveCharacter class CorpStatsQuerySet(models.QuerySet): @@ -9,9 +7,9 @@ class CorpStatsQuerySet(models.QuerySet): if user.is_superuser: return self - auth = AuthServicesInfo.objects.get(user=user) try: - char = EveCharacter.objects.get(character_id=auth.main_char_id) + assert user.profile.main_character + char = user.profile.main_character # build all accepted queries queries = [] if user.has_perm('corputils.view_corp_corpstats'): @@ -30,7 +28,7 @@ class CorpStatsQuerySet(models.QuerySet): else: # not allowed to see any return self.none() - except EveCharacter.DoesNotExist: + except AssertionError: return self.none() diff --git a/corputils/migrations/0003_auto_20170322_2335.py b/corputils/migrations/0003_auto_20170322_2335.py new file mode 100644 index 00000000..ad985985 --- /dev/null +++ b/corputils/migrations/0003_auto_20170322_2335.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-03-22 23:35 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('corputils', '0002_migrate_permissions'), + ] + + operations = [ + migrations.AlterModelOptions( + name='corpstats', + options={'permissions': (('corp_apis', 'Can view API keys of members of their corporation.'), ('alliance_apis', 'Can view API keys of members of their alliance.'), ('blue_apis', 'Can view API keys of members of blue corporations.'), ('view_corp_corpstats', 'Can view corp stats of their corporation.'), ('view_alliance_corpstats', 'Can view corp stats of members of their alliance.'), ('view_blue_corpstats', 'Can view corp stats of blue corporations.')), 'verbose_name': 'corp stats', 'verbose_name_plural': 'corp stats'}, + ), + ] diff --git a/corputils/models.py b/corputils/models.py index 6f04238b..432e03c2 100644 --- a/corputils/models.py +++ b/corputils/models.py @@ -1,11 +1,11 @@ from __future__ import unicode_literals from django.utils.encoding import python_2_unicode_compatible from django.db import models -from eveonline.models import EveCorporationInfo, EveCharacter, EveApiKeyPair +from eveonline.models import EveCorporationInfo, EveCharacter from esi.models import Token from esi.errors import TokenError from notifications import notify -from authentication.models import AuthServicesInfo +from authentication.models import CharacterOwnership, UserProfile from bravado.exception import HTTPForbidden from corputils.managers import CorpStatsManager from operator import attrgetter @@ -97,62 +97,32 @@ class CorpStats(models.Model): def member_names(self): return [name for id, name in self.members.items()] - def show_apis(self, user): - auth = AuthServicesInfo.objects.get(user=user) - if auth.main_char_id: - try: - char = EveCharacter.objects.get(character_id=auth.main_char_id) - if char.corporation_id == self.corp.corporation_id and user.has_perm('corputils.corp_apis'): - return True - if self.corp.alliance and char.alliance_id == self.corp.alliance.alliance_id and user.has_perm( - 'corputils.alliance_apis'): - return True - if user.has_perm('corputils.blue_apis') and self.corp.is_blue: - return True - except EveCharacter.DoesNotExist: - pass - return user.is_superuser - - def entered_apis(self): - return EveCharacter.objects.filter(character_id__in=self.member_ids).exclude(api_id__isnull=True).count() - def member_count(self): return len(self.members) - def user_count(self, members): + @staticmethod + def user_count(members): mainchars = [] for member in members: if hasattr(member.main, 'character_name'): mainchars.append(member.main.character_name) return len(set(mainchars)) + def registered_characters(self): + return len(CharacterOwnership.objects.filter(character__character_id__in=self.member_ids)) + @python_2_unicode_compatible class MemberObject(object): - def __init__(self, character_id, character_name, show_apis=False): + def __init__(self, character_id, character_name): self.character_id = character_id self.character_name = character_name try: char = EveCharacter.objects.get(character_id=character_id) - auth = AuthServicesInfo.objects.get(user=char.user) - try: - self.main = EveCharacter.objects.get(character_id=auth.main_char_id) - self.main_user = self.main.character_name - except EveCharacter.DoesNotExist: - self.main = None - self.main_user = '' - api = EveApiKeyPair.objects.get(api_id=char.api_id) + self.main_user = char.character_ownership.user + self.main = self.main_user.profile.main_character self.registered = True - if show_apis: - self.api = api - else: - self.api = None - except (EveCharacter.DoesNotExist, AuthServicesInfo.DoesNotExist): + except (EveCharacter.DoesNotExist, CharacterOwnership.DoesNotExist, UserProfile.DoesNotExist, AttributeError): self.main = None - self.api = None - self.registered = False - self.main_user = '' - except EveApiKeyPair.DoesNotExist: - self.api = None self.registered = False self.main_user = '' @@ -162,9 +132,8 @@ class CorpStats(models.Model): def portrait_url(self, size=32): return "https://image.eveonline.com/Character/%s_%s.jpg" % (self.character_id, size) - def get_member_objects(self, user): - show_apis = self.show_apis(user) - member_list = [CorpStats.MemberObject(id, name, show_apis=show_apis) for id, name in self.members.items()] + def get_member_objects(self): + member_list = [CorpStats.MemberObject(id, name) for id, name in self.members.items()] outlist = sorted([m for m in member_list if m.main_user], key=attrgetter('main_user', 'character_name')) outlist = outlist + sorted([m for m in member_list if not m.main_user], key=attrgetter('character_name')) return outlist @@ -180,8 +149,7 @@ class CorpStats(models.Model): self.can_update = corpstats.can_update(user) self.total_members = len(self.members) self.total_users = corpstats.user_count(self.members) - self.registered_members = corpstats.entered_apis() - self.show_apis = corpstats.show_apis(user) + self.registered_members = corpstats.registered_characters() self.last_updated = corpstats.last_update def __str__(self): diff --git a/corputils/templates/corputils/base.html b/corputils/templates/corputils/base.html index e93921fa..bbc5ef1a 100644 --- a/corputils/templates/corputils/base.html +++ b/corputils/templates/corputils/base.html @@ -1,4 +1,4 @@ -{% extends 'public/base.html' %} +{% extends 'registered/base.html' %} {% load i18n %} {% block title %}{% trans "Corporation Member Data" %}{% endblock %} {% block page_title %}{% trans "Corporation Member Data" %}{% endblock %} diff --git a/corputils/templates/corputils/corpstats.html b/corputils/templates/corputils/corpstats.html index df1f0b76..92c29e11 100644 --- a/corputils/templates/corputils/corpstats.html +++ b/corputils/templates/corputils/corpstats.html @@ -58,9 +58,6 @@ {% trans "Character" %} - {% if corpstats.show_apis %} - API - {% endif %} {% trans "zKillboard" %} {% trans "Main Character" %} {% trans "Main Corporation" %} @@ -70,13 +67,6 @@ {{ member.character_name }} - {% if corpstats.show_apis %} - {% if member.api %} - {{ member.api|api_link:'label label-primary' }} - {% else %} - - {% endif %} - {% endif %} {% trans "Killboard" %} {{ member.main.character_name }} {{ member.main.corporation_name }} diff --git a/corputils/templates/corputils/search.html b/corputils/templates/corputils/search.html index 413fb0ea..c80d36ec 100644 --- a/corputils/templates/corputils/search.html +++ b/corputils/templates/corputils/search.html @@ -16,7 +16,6 @@ {% trans "Character" %} {% trans "Corporation" %} - {% trans "API" %} {% trans "zKillboard" %} {% trans "Main Character" %} {% trans "Main Corporation" %} @@ -27,11 +26,6 @@ {{ result.1.character_name }} {{ result.0.corp.corporation_name }} - {% if result.1.api %} - {{ result.1.api|api_link:"label label-primary" }} - {% else %} - - {% endif %} {% trans "Killboard" %} {{ result.1.main.character_name }} {{ result.1.main.corporation_name }} diff --git a/corputils/views.py b/corputils/views.py index 31f5cc1a..a9d63563 100644 --- a/corputils/views.py +++ b/corputils/views.py @@ -1,5 +1,4 @@ from __future__ import unicode_literals -from django.conf import settings from django.contrib.auth.decorators import login_required, permission_required, user_passes_test from django.shortcuts import render, redirect, get_object_or_404 from django.contrib import messages @@ -133,7 +132,7 @@ def corpstats_search(request): search_string.lower() in corpstats.members[member_id].lower()] for s in similar: results.append( - (corpstats, CorpStats.MemberObject(s[0], s[1], show_apis=corpstats.show_apis(request.user)))) + (corpstats, CorpStats.MemberObject(s[0], s[1]))) page = request.GET.get('page', 1) results = sorted(results, key=lambda x: x[1].character_name) results_page = get_page(results, page) diff --git a/eveonline/admin.py b/eveonline/admin.py index 21fa6ed5..6c1f2623 100644 --- a/eveonline/admin.py +++ b/eveonline/admin.py @@ -1,46 +1,31 @@ from __future__ import unicode_literals from django.contrib import admin - +from django.core.exceptions import ObjectDoesNotExist 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', 'characters'] - - @staticmethod - def characters(obj): - return ', '.join(sorted([c.character_name for c in EveCharacter.objects.filter(api_id=obj.api_id)])) - - def get_search_results(self, request, queryset, search_term): - queryset, use_distinct = super(EveApiKeyPairAdmin, self).get_search_results(request, queryset, search_term) - chars = EveCharacter.objects.filter(character_name__icontains=search_term) - queryset |= EveApiKeyPair.objects.filter(api_id__in=[char.api_id for char in chars if bool(char.api_id)]) - return queryset, use_distinct - - class EveCharacterAdmin(admin.ModelAdmin): - search_fields = ['character_name', 'corporation_name', 'alliance_name', 'user__username', 'api_id'] + search_fields = ['character_name', 'corporation_name', 'alliance_name', 'character_ownership__user__username'] list_display = ('character_name', 'corporation_name', 'alliance_name', 'user', 'main_character') + @staticmethod + def user(obj): + try: + return obj.character_ownership.user + except (AttributeError, ObjectDoesNotExist): + return None + @staticmethod def main_character(obj): - if obj.user: - auth = AuthServicesInfo.objects.get(user=obj.user) - if auth and auth.main_char_id: - try: - return EveCharacter.objects.get(character_id=auth.main_char_id) - except EveCharacter.DoesNotExist: - pass - return None + try: + return obj.character_ownership.user.profile.main_character + except (AttributeError, ObjectDoesNotExist): + return None admin.site.register(EveCharacter, EveCharacterAdmin) -admin.site.register(EveApiKeyPair, EveApiKeyPairAdmin) diff --git a/eveonline/forms.py b/eveonline/forms.py deleted file mode 100644 index efffdbc7..00000000 --- a/eveonline/forms.py +++ /dev/null @@ -1,52 +0,0 @@ -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 EveApiKeyPair -import evelink - -import logging - -logger = logging.getLogger(__name__) - - -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']) - return api_id - except: - raise forms.ValidationError("API ID must be a number") - - def clean(self): - if 'api_id' not in self.cleaned_data or 'api_key' not in self.cleaned_data: - # need to check if api_id and vcode in cleaned_data because - # if they fail, they get removed from the dict but this method still happens - return self.cleaned_data - - 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']) - if EveApiKeyPair.objects.get(api_id=self.cleaned_data['api_id']).user: - # allow orphaned APIs to proceed to SSO validation upon re-entry - 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'])) - raise forms.ValidationError('Error while checking API key (%s)' % e.code) diff --git a/eveonline/managers.py b/eveonline/managers.py index ca828c1d..70cbba0b 100644 --- a/eveonline/managers.py +++ b/eveonline/managers.py @@ -1,11 +1,8 @@ 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 authentication.models import AuthServicesInfo -from eveonline.providers import eve_adapter_factory, EveXmlProvider -from services.managers.eve_api_manager import EveApiManager +from eveonline.providers import eve_adapter_factory import logging logger = logging.getLogger(__name__) @@ -25,11 +22,11 @@ class EveManager(object): return cls.get_adapter().get_character(character_id) @staticmethod - def create_character(id, user, api_id): - return EveManager.create_character_obj(EveManager.get_character(id), user, api_id) + def create_character(id): + return EveManager.create_character_obj(EveManager.get_character(id)) @staticmethod - def create_character_obj(character, user, api_id): + def create_character_obj(character,): return EveCharacter.objects.create( character_id=character.id, character_name=character.name, @@ -38,8 +35,6 @@ class EveManager(object): corporation_ticker=character.corp.ticker, alliance_id=character.alliance.id, alliance_name=character.alliance.name, - user=user, - api_id=api_id, ) @staticmethod @@ -58,19 +53,6 @@ class EveManager(object): model.save() return model - @staticmethod - def create_api_keypair(api_id, api_key, user_id): - logger.debug("Creating api keypair id %s for user_id %s" % (api_id, user_id)) - if not EveApiKeyPair.objects.filter(api_id=api_id).exists(): - api_pair = EveApiKeyPair() - api_pair.api_id = api_id - api_pair.api_key = api_key - api_pair.user = user_id - api_pair.save() - logger.info("Created api keypair id %s for user %s" % (api_id, user_id)) - else: - logger.warn("Attempting to create existing api keypair with id %s" % api_id) - @classmethod def get_alliance(cls, alliance_id): return cls.get_adapter().get_alliance(alliance_id) @@ -157,82 +139,6 @@ class EveManager(object): def get_itemtype(cls, type_id): return cls.get_adapter().get_itemtype(type_id) - @staticmethod - def get_characters_from_api(api): - char_result = EveApiManager.get_characters_from_api(api.api_id, api.api_key).result - provider = EveXmlProvider(adapter=EveManager.get_adapter()) - return [provider._build_character(result) for id, result in char_result.items()] - - @staticmethod - def get_api_key_pairs(user): - if EveApiKeyPair.objects.filter(user=user).exists(): - logger.debug("Returning api keypairs for user %s" % user) - return EveApiKeyPair.objects.filter(user=user) - else: - logger.debug("No api keypairs found for user %s" % user) - - @staticmethod - def get_all_api_key_pairs(): - if EveApiKeyPair.objects.exists(): - logger.debug("Returning all api keypairs.") - return EveApiKeyPair.objects.all() - else: - logger.debug("No api keypairs found.") - - @staticmethod - def check_if_api_key_pair_exist(api_id): - if EveApiKeyPair.objects.filter(api_id=api_id).exists(): - logger.debug("Determined api id %s exists." % api_id) - return True - else: - logger.debug("Determined api id %s does not exist." % api_id) - return False - - @staticmethod - def check_if_api_key_pair_is_new(api_id, fudge_factor): - if EveApiKeyPair.objects.count() == 0: - 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)) - return False - else: - logger.debug("api key (%d) is new. Accepting" % api_id) - return True - - @staticmethod - def delete_api_key_pair(api_id, user_id): - logger.debug("Deleting api id %s" % api_id) - if EveApiKeyPair.objects.filter(api_id=api_id).exists(): - # Check that its owned by our user_id - apikeypair = EveApiKeyPair.objects.get(api_id=api_id) - if apikeypair.user.id == user_id: - 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)) - else: - logger.warn("Unable to locate api id %s - cannot delete." % api_id) - - @staticmethod - def delete_characters_by_api_id(api_id, user_id): - logger.debug("Deleting all characters associated with api id %s" % api_id) - if EveCharacter.objects.filter(api_id=api_id).exists(): - # Check that its owned by our user_id - characters = EveCharacter.objects.filter(api_id=api_id) - logger.debug("Got user %s characters %s from api %s" % (user_id, characters, api_id)) - for char in characters: - if char.user.id == user_id: - 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)) - @staticmethod def check_if_character_exist(char_name): return EveCharacter.objects.filter(character_name=char_name).exists() @@ -256,16 +162,6 @@ class EveManager(object): return None - @staticmethod - def get_main_character(user): - """ - Get a characters main - :param user: django.contrib.auth.models.User - :return: EveCharacter - """ - authserviceinfo = AuthServicesInfo.objects.get(user=user) - return EveManager.get_character_by_id(authserviceinfo.main_char_id) - @staticmethod def get_characters_by_api_id(api_id): return EveCharacter.objects.filter(api_id=api_id) diff --git a/eveonline/migrations/0008_remove_apikeys.py b/eveonline/migrations/0008_remove_apikeys.py new file mode 100644 index 00000000..158fccaf --- /dev/null +++ b/eveonline/migrations/0008_remove_apikeys.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-03-22 23:09 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('eveonline', '0007_unique_id_name'), + ] + + operations = [ + migrations.RemoveField( + model_name='eveapikeypair', + name='user', + ), + migrations.RemoveField( + model_name='eveallianceinfo', + name='is_blue', + ), + migrations.RemoveField( + model_name='evecharacter', + name='api_id', + ), + migrations.RemoveField( + model_name='evecharacter', + name='user', + ), + migrations.RemoveField( + model_name='evecorporationinfo', + name='is_blue', + ), + migrations.DeleteModel( + name='EveApiKeyPair', + ), + ] diff --git a/eveonline/models.py b/eveonline/models.py index 1632d5c4..ea09aa28 100644 --- a/eveonline/models.py +++ b/eveonline/models.py @@ -1,7 +1,6 @@ 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 @@ -13,31 +12,17 @@ class EveCharacter(models.Model): corporation_ticker = models.CharField(max_length=254) alliance_id = models.CharField(max_length=254, blank=True, null=True, default='') alliance_name = models.CharField(max_length=254, blank=True, null=True, default='') - api_id = models.CharField(max_length=254) - user = models.ForeignKey(User, blank=True, null=True) def __str__(self): return self.character_name -@python_2_unicode_compatible -class EveApiKeyPair(models.Model): - api_id = models.CharField(max_length=254, unique=True) - api_key = models.CharField(max_length=254) - user = models.ForeignKey(User, blank=True, null=True) - sso_verified = models.BooleanField(default=False) - - def __str__(self): - return self.api_id - - @python_2_unicode_compatible class EveAllianceInfo(models.Model): alliance_id = models.CharField(max_length=254, unique=True) alliance_name = models.CharField(max_length=254, unique=True) alliance_ticker = models.CharField(max_length=254) executor_corp_id = models.CharField(max_length=254) - is_blue = models.BooleanField(default=False) def __str__(self): return self.alliance_name @@ -49,7 +34,6 @@ class EveCorporationInfo(models.Model): corporation_name = models.CharField(max_length=254, unique=True) corporation_ticker = models.CharField(max_length=254) member_count = models.IntegerField() - is_blue = models.BooleanField(default=False) alliance = models.ForeignKey(EveAllianceInfo, blank=True, null=True) def __str__(self): diff --git a/eveonline/providers.py b/eveonline/providers.py index 391bb41c..90cc491d 100644 --- a/eveonline/providers.py +++ b/eveonline/providers.py @@ -330,9 +330,9 @@ class EveXmlProvider(EveProvider): self.adapter, id, corpinfo['name'], + corpinfo['ticker'], corpinfo['ceo']['id'], corpinfo['members']['current'], - corpinfo['ticker'], corpinfo['alliance']['id'] if corpinfo['alliance'] else None, ) return model diff --git a/eveonline/tasks.py b/eveonline/tasks.py index d15ab692..81a9b021 100644 --- a/eveonline/tasks.py +++ b/eveonline/tasks.py @@ -1,123 +1,29 @@ 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 eveonline.providers import eve_adapter_factory, ObjectNotFound -from authentication.tasks import set_state +from eveonline.providers import ObjectNotFound 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 = EveManager.get_characters_from_api(api) - for c in characters: - try: - EveManager.update_character_obj(c) - except EveCharacter.DoesNotExist: - logger.debug("API key %s has a new character on the account: %s" % (api.api_id, c)) - EveManager.create_character_obj(c, 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 [c.id for c in characters]: - 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 - except EveApiManager.ApiServerUnreachableError as e: - logger.warn("Error updating API %s\n%s" % (api.api_id, str(e))) - 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") +def update_corp(corp_id, is_blue=None): + EveManager.update_corporation(corp_id, is_blue=is_blue) @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(user=user) - 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(): - if not EveApiManager.check_if_api_server_online(): - logger.warn("Aborted scheduled API key refresh: API server unreachable") - return - - for u in User.objects.all(): - refresh_user_apis.delay(u) - - -@task -def update_corp(id, is_blue=None): - EveManager.update_corporation(id, is_blue=is_blue) - - -@task -def update_alliance(id, is_blue=None): - EveManager.update_alliance(id, is_blue=is_blue) - EveManager.populate_alliance(id) +def update_alliance(alliance_id, is_blue=None): + EveManager.update_alliance(alliance_id, is_blue=is_blue) + EveManager.populate_alliance(alliance_id) @periodic_task(run_every=crontab(minute=0, hour="*/2")) def run_corp_update(): - if not EveApiManager.check_if_api_server_online(): - logger.warn("Aborted updating corp and alliance models: API server unreachable") - return - # generate member corps for corp_id in settings.STR_CORP_IDS + settings.STR_BLUE_CORP_IDS: is_blue = True if corp_id in settings.STR_BLUE_CORP_IDS else False @@ -151,72 +57,3 @@ def run_corp_update(): for alliance in EveAllianceInfo.objects.exclude( alliance_id__in=settings.STR_ALLIANCE_IDS + settings.STR_BLUE_ALLIANCE_IDS): update_alliance.delay(alliance.alliance_id) - - try: - # create standings - standings = EveApiManager.get_corp_standings() - if standings: - standings = standings[settings.STANDING_LEVEL] - for standing in standings: - if float(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: - EveManager.create_alliance(standing, is_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) - EveManager.create_corporation(standing, is_blue=True) - - # 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() - elif alliance.alliance_id not in settings.STR_BLUE_ALLIANCE_IDS: - 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() - elif corp.corporation_id not in settings.STR_BLUE_CORP_IDS: - 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() - except evelink.api.APIError as e: - logger.error("Model update failed with error code %s" % e.code) - - # delete unnecessary alliance models - EveAllianceInfo.objects.filter(is_blue=False).exclude(alliance_id__in=settings.STR_ALLIANCE_IDS).delete() - - # delete unnecessary corp models - EveCorporationInfo.objects.filter(is_blue=False).exclude(corporation_id__in=settings.STR_CORP_IDS).exclude( - alliance__alliance_id__in=settings.STR_ALLIANCE_IDS).delete() diff --git a/eveonline/templatetags/eveonline_extras.py b/eveonline/templatetags/eveonline_extras.py deleted file mode 100644 index 2e9d349f..00000000 --- a/eveonline/templatetags/eveonline_extras.py +++ /dev/null @@ -1,17 +0,0 @@ -from django import template -from django.conf import settings -from django.utils.safestring import mark_safe - -register = template.Library() - - -@register.filter(name='api_link') -def api_link(api, style_class): - if settings.API_KEY_AUDIT_URL: - url = settings.API_KEY_AUDIT_URL.format(api_id=api.api_id, vcode=api.api_key, pk=api.pk) - element = "{api_id}".format(url=url, style=style_class, - api_id=api.api_id) - else: - element = "{api_id}".format( - style=style_class, prompt='"Verification Code"', vcode='"%s"' % api.api_key, api_id=api.api_id) - return mark_safe(element) diff --git a/eveonline/views.py b/eveonline/views.py index ae585464..73d342bc 100755 --- a/eveonline/views.py +++ b/eveonline/views.py @@ -1,176 +1,3 @@ from __future__ import unicode_literals -from django.shortcuts import render, redirect, get_object_or_404 -from django.contrib.auth.decorators import login_required -from django.contrib import messages -from django.utils.translation import ugettext_lazy as _ -from eveonline.forms import UpdateKeyForm -from eveonline.managers import EveManager -from authentication.managers import AuthServicesInfoManager -from services.managers.eve_api_manager import EveApiManager -from eveonline.models import EveApiKeyPair, EveCharacter -from authentication.models import AuthServicesInfo -from authentication.tasks import set_state -from eveonline.tasks import refresh_api -from esi.decorators import token_required -from django.conf import settings -import logging - -logger = logging.getLogger(__name__) -@login_required -def add_api_key(request): - logger.debug("add_api_key called by user %s" % request.user) - if request.method == 'POST': - form = UpdateKeyForm(request.user, request.POST) - logger.debug("Request type POST with form valid: %s" % form.is_valid()) - if form.is_valid(): - if EveApiKeyPair.objects.filter(api_id=form.cleaned_data['api_id'], - api_key=form.cleaned_data['api_key']).exists(): - # allow orphaned keys to proceed to SSO validation upon re-entry - api_key = EveApiKeyPair.objects.get(api_id=form.cleaned_data['api_id'], - api_key=form.cleaned_data['api_key']) - elif EveApiKeyPair.objects.filter(api_id=form.cleaned_data['api_id']).exists(): - logger.warn('API %s re-added with different vcode.' % form.cleaned_data['api_id']) - EveApiKeyPair.objects.filter(api_id=form.cleaned_data['api_id']).delete() - api_key = EveApiKeyPair.objects.create(api_id=form.cleaned_data['api_id'], - api_key=form.cleaned_data['api_key']) - else: - api_key = EveApiKeyPair.objects.create(api_id=form.cleaned_data['api_id'], - api_key=form.cleaned_data['api_key']) - owner = None - if not settings.API_SSO_VALIDATION: - # set API and character owners if SSO validation not requested - api_key.user = request.user - api_key.save() - owner = request.user - # Grab characters associated with the key pair - characters = EveManager.get_characters_from_api(api_key) - [EveManager.create_character_obj(c, owner, api_key.api_id) for c in characters if - not EveCharacter.objects.filter(character_id=c.id).exists()] - logger.info("Successfully processed api add form for user %s" % request.user) - if not settings.API_SSO_VALIDATION: - messages.success(request, _('Added API key %(apiid)s to your account.') % {"apiid": form.cleaned_data['api_id']}) - auth = AuthServicesInfo.objects.get(user=request.user) - if not auth.main_char_id: - return redirect('auth_characters') - return redirect("auth_dashboard") - else: - logger.debug('Requesting SSO validation of API %s by user %s' % (api_key.api_id, request.user)) - return render(request, 'registered/apisso.html', context={'api': api_key}) - else: - logger.debug("Form invalid: returning to form.") - else: - logger.debug("Providing empty update key form for user %s" % request.user) - form = UpdateKeyForm(request.user) - context = {'form': form, 'apikeypairs': EveManager.get_api_key_pairs(request.user.id)} - return render(request, 'registered/addapikey.html', context=context) - - -@login_required -@token_required(new=True) -def api_sso_validate(request, token, api_id): - logger.debug('api_sso_validate called by user %s for api %s' % (request.user, api_id)) - api = get_object_or_404(EveApiKeyPair, api_id=api_id) - if api.user and api.user != request.user: - logger.warning('User %s attempting to take ownership of api %s from %s' % (request.user, api_id, api.user)) - messages.warning(request, _('API %(apiid)s already claimed by user %(user)s') % {"apiid": api_id, "user": api.user}) - return redirect('auth_dashboard') - elif api.sso_verified: - logger.debug('API %s has already been verified.' % api_id) - messages.info(request, _('API %(apiid)s has already been verified') % {"apiid": api_id}) - return redirect('auth_dashboard') - logger.debug('API %s has not been verified. Checking if token for %s matches.' % (api_id, token.character_name)) - characters = EveApiManager.get_characters_from_api(api.api_id, api.api_key).result - if token.character_id in characters: - api.user = request.user - api.sso_verified = True - api.save() - EveCharacter.objects.filter(character_id__in=characters).update(user=request.user, api_id=api_id) - messages.success(request, _('Confirmed ownership of API %(apiid)s') % {"apiid": api.api_id}) - auth = AuthServicesInfo.objects.get(user=request.user) - if not auth.main_char_id: - return redirect('auth_characters') - return redirect('auth_dashboard') - else: - messages.warning(request, _('%(character)s not found on API %(apiid)s. Please SSO as a character on the API.') % { - "character": token.character_name, "apiid": api.api_id}) - return render(request, 'registered/apisso.html', context={'api': api}) - - -@login_required -def dashboard_view(request): - logger.debug("dashboard_view called by user %s" % request.user) - auth_info = AuthServicesInfo.objects.get(user=request.user) - apikeypairs = EveManager.get_api_key_pairs(request.user.id) - sso_validation = settings.API_SSO_VALIDATION or False - api_chars = [] - - if apikeypairs: - for api in apikeypairs: - api_chars.append({ - 'id': api.api_id, - 'sso_verified': api.sso_verified if sso_validation else True, - 'characters': EveCharacter.objects.filter(api_id=api.api_id), - }) - - context = { - 'main': EveManager.get_character_by_id(auth_info.main_char_id), - 'apis': api_chars, - 'api_sso_validation': settings.API_SSO_VALIDATION or False, - } - return render(request, 'registered/dashboard.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 = AuthServicesInfo.objects.get(user=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 %(apiid)s') % {"apiid": api_id}) - logger.info("Succesfully processed api delete request by user %s for api %s" % (request.user, api_id)) - if not EveCharacter.objects.filter(character_id=authinfo.main_char_id).exists(): - authinfo.main_char_id = None - authinfo.save() - set_state(request.user) - return redirect("auth_dashboard") - - -@login_required -def characters_view(request): - logger.debug("characters_view called by user %s" % request.user) - render_items = {'characters': EveCharacter.objects.filter(user=request.user), - 'authinfo': AuthServicesInfo.objects.get(user=request.user)} - 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 EveCharacter.objects.filter(character_id=char_id).exists() and EveCharacter.objects.get( - character_id=char_id).user == request.user: - AuthServicesInfoManager.update_main_char_id(char_id, request.user) - messages.success(request, _('Changed main character ID to %(charid)s') % {"charid": char_id}) - set_state(request.user) - return redirect("auth_dashboard") - messages.error(request, _('Failed to change main character - selected character is not owned by your account.')) - return redirect("auth_characters") - - -@login_required -def user_refresh_api(request, api_id): - logger.debug("user_refresh_api called by user %s for api id %s" % (request.user, api_id)) - if EveApiKeyPair.objects.filter(api_id=api_id).exists(): - 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 %(apiid)s') % {"apiid": 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 %(apiid)s') % {"apiid": api_id}) - logger.warn("User %s unable to refresh api id %s - api key not found" % (request.user, api_id)) - return redirect("auth_dashboard") diff --git a/fleetactivitytracking/forms.py b/fleetactivitytracking/forms.py index 4d5c256d..4a043fd6 100644 --- a/fleetactivitytracking/forms.py +++ b/fleetactivitytracking/forms.py @@ -1,11 +1,11 @@ from __future__ import unicode_literals from django import forms -from optimer.models import optimer +from optimer.models import OpTimer from django.utils.translation import ugettext_lazy as _ def get_fleet_list(): - fleets = optimer.objects.all() + fleets = OpTimer.objects.all() fleetlist = [("None", "None")] for fleet in fleets: fleetlist.append((fleet.operation_name, fleet.operation_name)) @@ -17,4 +17,4 @@ 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')) + fleet = forms.ModelChoiceField(label=_("Fleet"), queryset=OpTimer.objects.all().order_by('operation_name')) diff --git a/fleetactivitytracking/migrations/0004_auto_20170322_2335.py b/fleetactivitytracking/migrations/0004_auto_20170322_2335.py new file mode 100644 index 00000000..d743e232 --- /dev/null +++ b/fleetactivitytracking/migrations/0004_auto_20170322_2335.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-03-22 23:35 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fleetactivitytracking', '0003_auto_20160906_2354'), + ] + + operations = [ + migrations.AlterField( + model_name='fatlink', + name='fleet', + field=models.CharField(default='', max_length=254), + ), + ] diff --git a/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html b/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html index 67d76c67..d000dd7d 100644 --- a/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html +++ b/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html @@ -1,4 +1,4 @@ -{% extends 'public/base.html' %} +{% extends 'registered/base.html' %} {% load i18n %} {% block title %}Fleet Participation{% endblock %} {% block page_title %}{% trans "Fleet Participation" %}{% endblock %} diff --git a/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html b/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html index d08e3873..9ad3f9b6 100644 --- a/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html +++ b/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html b/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html index d30ac0f4..5a3a9b20 100644 --- a/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html +++ b/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html b/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html index baa7dace..766b7bd2 100644 --- a/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html +++ b/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalstatisticsview.html b/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalstatisticsview.html index 18cec487..d098d656 100644 --- a/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalstatisticsview.html +++ b/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalstatisticsview.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html b/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html index 436f1be0..d7b77bc7 100644 --- a/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html +++ b/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html b/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html index ed85490a..8b1fa240 100644 --- a/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html +++ b/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/fleetactivitytracking/views.py b/fleetactivitytracking/views.py index 067d91c9..947011d6 100644 --- a/fleetactivitytracking/views.py +++ b/fleetactivitytracking/views.py @@ -1,6 +1,6 @@ from __future__ import unicode_literals from django.conf import settings -from django.shortcuts import render, redirect +from django.shortcuts import render, redirect, get_object_or_404 from django.core.exceptions import ObjectDoesNotExist from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import permission_required @@ -197,58 +197,53 @@ def fatlink_monthly_personal_statistics_view(request, year, month, char_id=None) @token_required( scopes=['esi-location.read_location.v1', 'esi-location.read_ship_type.v1', 'esi-universe.read_structures.v1']) def click_fatlink_view(request, token, hash, fatname): - try: - fatlink = Fatlink.objects.filter(hash=hash)[0] + fatlink = get_object_or_404(Fatlink, hash=hash, name=fatname) - if (timezone.now() - fatlink.fatdatetime) < datetime.timedelta(seconds=(fatlink.duration * 60)): + if (timezone.now() - fatlink.fatdatetime) < datetime.timedelta(seconds=(fatlink.duration * 60)): - character = EveManager.get_character_by_id(token.character_id) + character = EveManager.get_character_by_id(token.character_id) - if character: - # get data - c = token.get_esi_client(Location='v1', Universe='v2') - location = c.Location.get_characters_character_id_location(character_id=token.character_id).result() - ship = c.Location.get_characters_character_id_ship(character_id=token.character_id).result() - location['solar_system_name'] = \ - c.Universe.get_universe_systems_system_id(system_id=location['solar_system_id']).result()[ + if character: + # get data + c = token.get_esi_client(Location='v1', Universe='v2') + location = c.Location.get_characters_character_id_location(character_id=token.character_id).result() + ship = c.Location.get_characters_character_id_ship(character_id=token.character_id).result() + location['solar_system_name'] = \ + c.Universe.get_universe_systems_system_id(system_id=location['solar_system_id']).result()[ + 'name'] + if location['structure_id']: + location['station_name'] = \ + c.Universe.get_universe_structures_structure_id(structure_id=location['structure_id']).result()[ 'name'] - if location['structure_id']: - location['station_name'] = \ - c.Universe.get_universe_structures_structure_id(structure_id=location['structure_id']).result()[ - 'name'] - elif location['station_id']: - location['station_name'] = \ - c.Universe.get_universe_stations_station_id(station_id=location['station_id']).result()['name'] - else: - location['station_name'] = "No Station" - ship['ship_type_name'] = EveManager.get_itemtype(ship['ship_type_id']).name - - fat = Fat() - fat.system = location['solar_system_name'] - fat.station = location['station_name'] - fat.shiptype = ship['ship_type_name'] - fat.fatlink = fatlink - fat.character = character - fat.user = character.user - try: - fat.full_clean() - fat.save() - messages.success(request, _('Fleet participation registered.')) - except ValidationError as e: - err_messages = [] - for errorname, message in e.message_dict.items(): - err_messages.append(message[0].decode()) - messages.error(request, ' '.join(err_messages)) + elif location['station_id']: + location['station_name'] = \ + c.Universe.get_universe_stations_station_id(station_id=location['station_id']).result()['name'] else: - context = {'character_id': token.character_id, - 'character_name': token.character_name} - return render(request, 'fleetactivitytracking/characternotexisting.html', context=context) + location['station_name'] = "No Station" + ship['ship_type_name'] = EveManager.get_itemtype(ship['ship_type_id']).name + + fat = Fat() + fat.system = location['solar_system_name'] + fat.station = location['station_name'] + fat.shiptype = ship['ship_type_name'] + fat.fatlink = fatlink + fat.character = character + fat.user = character.user + try: + fat.full_clean() + fat.save() + messages.success(request, _('Fleet participation registered.')) + except ValidationError as e: + err_messages = [] + for errorname, message in e.message_dict.items(): + err_messages.append(message[0].decode()) + messages.error(request, ' '.join(err_messages)) else: - messages.error(request, _('FAT link has expired.')) - except (ObjectDoesNotExist, KeyError): - logger.exception("Failed to process FAT link.") - messages.error(request, _('Invalid FAT link.')) - return redirect('auth_fatlink_view') + context = {'character_id': token.character_id, + 'character_name': token.character_name} + return render(request, 'fleetactivitytracking/characternotexisting.html', context=context) + else: + messages.error(request, _('FAT link has expired.')) @login_required diff --git a/fleetup/views.py b/fleetup/views.py index fbd832d6..69e8cb51 100755 --- a/fleetup/views.py +++ b/fleetup/views.py @@ -5,7 +5,6 @@ from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import permission_required from django.template.defaulttags import register from fleetup.managers import FleetUpManager -from authentication.decorators import members_and_blues import logging @@ -18,7 +17,7 @@ def get_item(dictionary, key): @login_required -@members_and_blues() +@permission_required('auth.view_fleetup') def fleetup_view(request): logger.debug("fleetup_view called by user %s" % request.user) @@ -35,6 +34,7 @@ def fleetup_view(request): @login_required @permission_required('auth.human_resources') +@permission_required('auth.view_fleetup') def fleetup_characters(request): logger.debug("fleetup_characters called by user %s" % request.user) @@ -46,7 +46,7 @@ def fleetup_characters(request): @login_required -@members_and_blues() +@permission_required('auth.view_fleetup') def fleetup_fittings(request): logger.debug("fleetup_fittings called by user %s" % request.user) fitting_list = FleetUpManager.get_fleetup_fittings() @@ -55,7 +55,7 @@ def fleetup_fittings(request): @login_required -@members_and_blues() +@permission_required('auth.view_fleetup') def fleetup_fitting(request, fittingnumber): logger.debug("fleetup_fitting called by user %s" % request.user) fitting_eft = FleetUpManager.get_fleetup_fitting_eft(fittingnumber) @@ -69,7 +69,7 @@ def fleetup_fitting(request, fittingnumber): @login_required -@members_and_blues() +@permission_required('auth.view_fleetup') def fleetup_doctrines(request): logger.debug("fleetup_doctrines called by user %s" % request.user) doctrines_list = FleetUpManager.get_fleetup_doctrines() @@ -78,7 +78,7 @@ def fleetup_doctrines(request): @login_required -@members_and_blues() +@permission_required('auth.view_fleetup') def fleetup_doctrine(request, doctrinenumber): logger.debug("fleetup_doctrine called by user %s" % request.user) doctrine = FleetUpManager.get_fleetup_doctrine(doctrinenumber) diff --git a/groupmanagement/managers.py b/groupmanagement/managers.py index 41188257..d675aff5 100644 --- a/groupmanagement/managers.py +++ b/groupmanagement/managers.py @@ -1,6 +1,5 @@ from django.contrib.auth.models import Group -from django.conf import settings -from authentication.managers import UserState + class GroupManager: def __init__(self): @@ -39,7 +38,7 @@ class GroupManager: :return: bool True if user can manage groups, False otherwise """ if user.is_authenticated: - return cls.has_management_permission(user) or (user.leads_groups.all() and UserState.member_state(user)) + return cls.has_management_permission(user) or user.leads_groups.all() return False @classmethod @@ -51,6 +50,5 @@ class GroupManager: :return: True if the user can manage the group """ if user.is_authenticated: - return cls.has_management_permission(user) or ( - user.leads_groups.filter(group=group).exists() and UserState.member_state(user)) + return cls.has_management_permission(user) or user.leads_groups.filter(group=group).exists() return False diff --git a/groupmanagement/views.py b/groupmanagement/views.py index 30fa5995..e472f40b 100755 --- a/groupmanagement/views.py +++ b/groupmanagement/views.py @@ -1,5 +1,5 @@ from __future__ import unicode_literals -from django.shortcuts import render, redirect +from django.shortcuts import render, redirect, get_object_or_404 from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import user_passes_test from django.contrib.auth.models import Group @@ -11,8 +11,6 @@ from django.core.exceptions import ObjectDoesNotExist, PermissionDenied from django.http import Http404 from groupmanagement.managers import GroupManager from groupmanagement.models import GroupRequest -from authentication.models import AuthServicesInfo -from authentication.managers import UserState from eveonline.managers import EveManager from django.utils.translation import ugettext_lazy as _ @@ -72,8 +70,8 @@ def group_membership(request): @user_passes_test(GroupManager.can_manage_groups) def group_membership_list(request, group_id): logger.debug("group_membership_list called by user %s for group id %s" % (request.user, group_id)) + group = get_object_or_404(Group, id=group_id) try: - group = Group.objects.get(id=group_id) # Check its a joinable group i.e. not corp or internal # And the user has permission to manage it @@ -88,11 +86,10 @@ def group_membership_list(request, group_id): members = list() for member in group.user_set.all().order_by('username'): - authinfo = AuthServicesInfo.objects.get(user=member) members.append({ 'user': member, - 'main_char': EveManager.get_character_by_id(authinfo.main_char_id) + 'main_char': member.profile.main_character }) render_items = {'group': group, 'members': members} @@ -105,9 +102,8 @@ def group_membership_list(request, group_id): def group_membership_remove(request, group_id, user_id): logger.debug("group_membership_remove called by user %s for group id %s on user id %s" % (request.user, group_id, user_id)) + group = get_object_or_404(Group, id=group_id) try: - group = Group.objects.get(id=group_id) - # Check its a joinable group i.e. not corp or internal # And the user has permission to manage it if not GroupManager.joinable_group(group) or not GroupManager.can_manage_group(request.user, group): @@ -134,8 +130,8 @@ def group_membership_remove(request, group_id, user_id): @user_passes_test(GroupManager.can_manage_groups) def group_accept_request(request, group_request_id): logger.debug("group_accept_request called by user %s for grouprequest id %s" % (request.user, group_request_id)) + group_request = get_object_or_404(GroupRequest, id=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) if not GroupManager.joinable_group(group_request.group) or \ @@ -169,9 +165,8 @@ def group_accept_request(request, group_request_id): @user_passes_test(GroupManager.can_manage_groups) def group_reject_request(request, group_request_id): logger.debug("group_reject_request called by user %s for group request id %s" % (request.user, group_request_id)) + group_request = get_object_or_404(GroupRequest, id=group_request_id) try: - group_request = GroupRequest.objects.get(id=group_request_id) - if not GroupManager.can_manage_group(request.user, group_request.group): raise PermissionDenied @@ -202,9 +197,8 @@ def group_reject_request(request, group_request_id): 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)) + group_request = get_object_or_404(GroupRequest, id=group_request_id) try: - group_request = GroupRequest.objects.get(id=group_request_id) - if not GroupManager.can_manage_group(request.user, group_request.group): raise PermissionDenied @@ -237,9 +231,8 @@ def group_leave_accept_request(request, group_request_id): 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)) + group_request = get_object_or_404(GroupRequest, id=group_request_id) try: - group_request = GroupRequest.objects.get(id=group_request_id) - if not GroupManager.can_manage_group(request.user, group_request.group): raise PermissionDenied @@ -307,12 +300,11 @@ def group_request_add(request, group_id): logger.info("%s joining %s as is an open group" % (request.user, group)) request.user.groups.add(group) return redirect("auth_groups") - auth_info = AuthServicesInfo.objects.get(user=request.user) grouprequest = GroupRequest() grouprequest.status = _('Pending') grouprequest.group = group grouprequest.user = request.user - grouprequest.main_char = EveManager.get_character_by_id(auth_info.main_char_id) + grouprequest.main_char = request.user.profile.main_character 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))) @@ -338,12 +330,11 @@ def group_request_leave(request, group_id): logger.info("%s leaving %s as is an open group" % (request.user, group)) request.user.groups.remove(group) return redirect("auth_groups") - auth_info = AuthServicesInfo.objects.get(user=request.user) grouprequest = GroupRequest() grouprequest.status = _('Pending') grouprequest.group = group grouprequest.user = request.user - grouprequest.main_char = EveManager.get_character_by_id(auth_info.main_char_id) + grouprequest.main_char = request.user.profile.main_character 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))) diff --git a/hrapplications/migrations/0002_auto_20170322_2335.py b/hrapplications/migrations/0002_auto_20170322_2335.py new file mode 100644 index 00000000..db7d274d --- /dev/null +++ b/hrapplications/migrations/0002_auto_20170322_2335.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-03-22 23:35 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('hrapplications', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='hrapplication', + name='about', + field=models.TextField(default=''), + ), + migrations.AlterField( + model_name='hrapplication', + name='character_name', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='hrapplication', + name='extra', + field=models.TextField(default=''), + ), + migrations.AlterField( + model_name='hrapplication', + name='full_api_id', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='hrapplication', + name='full_api_key', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='hrapplication', + name='is_a_spi', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='hrapplicationcomment', + name='comment', + field=models.CharField(default='', max_length=254), + ), + ] diff --git a/hrapplications/models.py b/hrapplications/models.py index c76e3da4..c5d6d5f4 100755 --- a/hrapplications/models.py +++ b/hrapplications/models.py @@ -5,8 +5,6 @@ from django.contrib.auth.models import User from eveonline.models import EveCharacter from eveonline.models import EveCorporationInfo -from eveonline.models import EveApiKeyPair -from authentication.models import AuthServicesInfo @python_2_unicode_compatible @@ -47,21 +45,12 @@ class Application(models.Model): @property def main_character(self): - try: - auth = AuthServicesInfo.objects.get(user=self.user) - char = EveCharacter.objects.get(character_id=auth.main_char_id) - return char - except: - return None + return self.user.profile.main_character @property def characters(self): return EveCharacter.objects.filter(user=self.user) - @property - def apis(self): - return EveApiKeyPair.objects.filter(user=self.user) - @property def reviewer_str(self): if self.reviewer_character: diff --git a/hrapplications/views.py b/hrapplications/views.py index d06b2050..9d1ad2b7 100755 --- a/hrapplications/views.py +++ b/hrapplications/views.py @@ -11,7 +11,6 @@ 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 import logging @@ -19,11 +18,7 @@ logger = logging.getLogger(__name__) def create_application_test(user): - auth = AuthServicesInfo.objects.get(user=user) - if auth.main_char_id: - return True - else: - return False + return bool(user.profile.main_character) @login_required @@ -31,13 +26,7 @@ def hr_application_management_view(request): logger.debug("hr_application_management_view called by user %s" % request.user) corp_applications = [] finished_corp_applications = [] - auth_info = AuthServicesInfo.objects.get(user=request.user) - main_char = None - if auth_info.main_char_id: - try: - main_char = EveCharacter.objects.get(character_id=auth_info.main_char_id) - except EveCharacter.DoesNotExist: - pass + main_char = request.user.profile.main_character if request.user.is_superuser: corp_applications = Application.objects.filter(approved=None) finished_corp_applications = Application.objects.exclude(approved=None) @@ -99,7 +88,6 @@ def hr_application_personal_view(request, app_id): 'buttons': False, 'comments': ApplicationComment.objects.filter(application=app), 'comment_form': HRApplicationCommentForm(), - 'apis': [], } return render(request, 'registered/hrapplicationview.html', context=context) else: @@ -141,17 +129,14 @@ def hr_application_view(request, app_id): return redirect(hr_application_view, app_id) else: logger.warn("User %s does not have permission to add ApplicationComments" % request.user) + return redirect(hr_application_view, app_id) else: logger.debug("Returning blank HRApplication comment form.") form = HRApplicationCommentForm() - apis = [] - if request.user.has_perm('hrapplications.view_apis'): - apis = app.apis context = { 'app': app, 'responses': ApplicationResponse.objects.filter(application=app), 'buttons': True, - 'apis': apis, 'comments': ApplicationComment.objects.filter(application=app), 'comment_form': form, } @@ -219,11 +204,9 @@ def hr_application_search(request): if request.user.is_superuser: app_list = Application.objects.all() else: - auth_info = AuthServicesInfo.objects.get(user=request.user) 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 EveCharacter.DoesNotExist: + app_list = Application.objects.filter(form__corp__corporation_id=request.user.profile.main_character.corporation_id) + except AttributeError: logger.warn( "User %s missing main character model: unable to filter applications to search" % request.user) for application in app_list: @@ -267,14 +250,8 @@ def hr_application_mark_in_progress(request, app_id): app = get_object_or_404(Application, pk=app_id) if not app.reviewer: logger.info("User %s marking %s in progress" % (request.user, app)) - auth_info = AuthServicesInfo.objects.get(user=request.user) - try: - character = EveCharacter.objects.get(character_id=auth_info.main_char_id) - 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.reviewer_character = request.user.profile.main_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)) diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index d5b4a232..8002abf5 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -1078,76 +1078,76 @@ msgstr "Aktualisiere SRP Menge" msgid "Saved changes to SRP fleet %(fleetname)s" msgstr "Änderungen der SRP flotte %(fleetname)s gespeichert" -#: stock/templates/public/base.html:85 +#: stock/templates/registered/base.html:85 msgid "Admin" msgstr "Admin" -#: stock/templates/public/base.html:87 +#: stock/templates/registered/base.html:87 msgid "Logout" msgstr "Ausloggen" -#: stock/templates/public/base.html:89 stock/templates/public/login.html:14 +#: stock/templates/registered/base.html:89 stock/templates/public/login.html:14 #: stock/templates/registration/password_reset_complete.html:49 msgid "Login" msgstr "Einloggen" -#: stock/templates/public/base.html:101 +#: stock/templates/registered/base.html:101 msgid "Main Navigation" msgstr "Haupmenü" -#: stock/templates/public/base.html:106 +#: stock/templates/registered/base.html:106 msgid " Dashboard" msgstr " Dashboard" -#: stock/templates/public/base.html:113 +#: stock/templates/registered/base.html:113 msgid " Groups" msgstr " Gruppen" -#: stock/templates/public/base.html:120 +#: stock/templates/registered/base.html:120 msgid " Help" msgstr " Hilfe" -#: stock/templates/public/base.html:126 +#: stock/templates/registered/base.html:126 msgid "Aux Navigation" msgstr "Zusatz Navigation" -#: stock/templates/public/base.html:131 +#: stock/templates/registered/base.html:131 msgid " Services" msgstr " Dienste" -#: stock/templates/public/base.html:140 +#: stock/templates/registered/base.html:140 msgid " Applications" msgstr " Bewerbungen" -#: stock/templates/public/base.html:148 +#: stock/templates/registered/base.html:148 msgid " Corporation Stats" msgstr " Korporationsstatistiken" -#: stock/templates/public/base.html:156 +#: stock/templates/registered/base.html:156 msgid " Group Management" msgstr " Gruppenverwaltung" -#: stock/templates/public/base.html:174 +#: stock/templates/registered/base.html:174 msgid " Fleet Operations" msgstr " Flottenoperationen" -#: stock/templates/public/base.html:181 +#: stock/templates/registered/base.html:181 msgid " Structure Timers" msgstr " Strukturen Timer" -#: stock/templates/public/base.html:188 +#: stock/templates/registered/base.html:188 msgid " Fleet Activity Tracking" msgstr " Flottenaktivitäts-Tracking" -#: stock/templates/public/base.html:194 +#: stock/templates/registered/base.html:194 msgid " Ship Replacement" msgstr " Schiff’s erstattung" -#: stock/templates/public/base.html:200 +#: stock/templates/registered/base.html:200 msgid "Util" msgstr "Werkzeuge" -#: stock/templates/public/base.html:204 +#: stock/templates/registered/base.html:204 #: stock/templates/registration/password_change_done.html:10 #: stock/templates/registration/password_change_form.html:9 #: stock/templates/registration/password_change_form.html:18 @@ -1155,7 +1155,7 @@ msgstr "Werkzeuge" msgid "Change Password" msgstr "Passwort ändern" -#: stock/templates/public/base.html:211 +#: stock/templates/registered/base.html:211 msgid " Fleet Broadcast Formatter" msgstr "Flottenübertragungen Formatierer " diff --git a/notifications/handlers.py b/notifications/handlers.py index 6404d522..dad51354 100644 --- a/notifications/handlers.py +++ b/notifications/handlers.py @@ -19,14 +19,15 @@ class NotificationHandler(logging.Handler): message += "\n\n" message = message + record.exc_text - users = User.objects.filter(Q(groups__permissions=perm) | Q(user_permissions=perm) | Q(is_superuser=True)).distinct() + users = User.objects.filter( + Q(groups__permissions=perm) | Q(user_permissions=perm) | Q(is_superuser=True)).distinct() for user in users: notify( user, "%s [%s:%s]" % (record.levelname, record.funcName, record.lineno), - level = str([item[0] for item in Notification.LEVEL_CHOICES if item[1] == record.levelname][0]), - message = message + level=str([item[0] for item in Notification.LEVEL_CHOICES if item[1] == record.levelname][0]), + message=message ) except Permission.DoesNotExist: pass diff --git a/notifications/migrations/0003_auto_20170322_2335.py b/notifications/migrations/0003_auto_20170322_2335.py new file mode 100644 index 00000000..c9af5bb9 --- /dev/null +++ b/notifications/migrations/0003_auto_20170322_2335.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-03-22 23:35 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('notifications', '0002_auto_20160910_1649'), + ] + + operations = [ + migrations.AlterField( + model_name='notification', + name='level', + field=models.CharField(choices=[('danger', 'CRITICAL'), ('danger', 'ERROR'), ('warning', 'WARN'), ('info', 'INFO'), ('success', 'DEBUG')], max_length=10), + ), + ] diff --git a/optimer/admin.py b/optimer/admin.py index fd962cbe..fff104db 100644 --- a/optimer/admin.py +++ b/optimer/admin.py @@ -1,6 +1,6 @@ from __future__ import unicode_literals from django.contrib import admin -from optimer.models import optimer +from optimer.models import OpTimer -admin.site.register(optimer) +admin.site.register(OpTimer) diff --git a/optimer/form.py b/optimer/form.py index 6e476677..5d622c86 100644 --- a/optimer/form.py +++ b/optimer/form.py @@ -3,7 +3,7 @@ from django import forms from django.utils.translation import ugettext_lazy as _ -class opForm(forms.Form): +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/0002_auto_20170322_2335.py b/optimer/migrations/0002_auto_20170322_2335.py new file mode 100644 index 00000000..4f950b01 --- /dev/null +++ b/optimer/migrations/0002_auto_20170322_2335.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-03-22 23:35 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('optimer', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='optimer', + name='details', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='optimer', + name='doctrine', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='optimer', + name='duration', + field=models.CharField(default='', max_length=25), + ), + migrations.AlterField( + model_name='optimer', + name='fc', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='optimer', + name='location', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='optimer', + name='operation_name', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='optimer', + name='system', + field=models.CharField(default='', max_length=254), + ), + ] diff --git a/optimer/models.py b/optimer/models.py index 32670bf0..0cc8a739 100644 --- a/optimer/models.py +++ b/optimer/models.py @@ -7,7 +7,7 @@ from datetime import datetime @python_2_unicode_compatible -class optimer(models.Model): +class OpTimer(models.Model): class Meta: ordering = ['start'] diff --git a/optimer/views.py b/optimer/views.py index e10c35e7..e0f8dec2 100644 --- a/optimer/views.py +++ b/optimer/views.py @@ -6,11 +6,8 @@ from django.utils.translation import ugettext_lazy as _ from django.shortcuts import get_object_or_404 from django.shortcuts import render, redirect from django.contrib import messages -from authentication.models import AuthServicesInfo -from eveonline.managers import EveManager -from optimer.form import opForm -from optimer.models import optimer -from authentication.decorators import members_and_blues +from optimer.form import OpForm +from optimer.models import OpTimer import logging @@ -18,11 +15,10 @@ logger = logging.getLogger(__name__) @login_required -@members_and_blues() @permission_required('auth.optimer_view') def optimer_view(request): logger.debug("optimer_view called by user %s" % request.user) - render_items = {'optimer': optimer.objects.all(), } + render_items = {'optimer': OpTimer.objects.all(), } return render(request, 'registered/operationmanagement.html', context=render_items) @@ -32,16 +28,15 @@ 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) + form = OpForm(request.POST) logger.debug("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 = AuthServicesInfo.objects.get(user=request.user) - character = EveManager.get_character_by_id(auth_info.main_char_id) + character = request.user.profile.main_character # handle valid form - op = optimer() + op = OpTimer() op.doctrine = form.cleaned_data['doctrine'] op.system = form.cleaned_data['system'] op.location = form.cleaned_data['location'] @@ -58,7 +53,7 @@ def add_optimer_view(request): return redirect("/optimer/") else: logger.debug("Returning new opForm") - form = opForm() + form = OpForm() render_items = {'form': form} @@ -69,14 +64,10 @@ def add_optimer_view(request): @permission_required('auth.optimer_management') def remove_optimer(request, optimer_id): logger.debug("remove_optimer called by user %s for operation id %s" % (request.user, optimer_id)) - if optimer.objects.filter(id=optimer_id).exists(): - 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 %(opname)s.') % {"opname": op.operation_name}) - else: - logger.error("Unable to delete optimer id %s for user %s - operation matching id not found." % ( - optimer_id, request.user)) + op = get_object_or_404(OpTimer, 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 %(opname)s.') % {"opname": op.operation_name}) return redirect("auth_optimer_view") @@ -84,13 +75,12 @@ def remove_optimer(request, optimer_id): @permission_required('auth.optimer_management') def edit_optimer(request, optimer_id): logger.debug("edit_optimer called by user %s for optimer id %s" % (request.user, optimer_id)) - op = get_object_or_404(optimer, id=optimer_id) + op = get_object_or_404(OpTimer, id=optimer_id) if request.method == 'POST': - form = opForm(request.POST) + 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 = AuthServicesInfo.objects.get(user=request.user) - character = EveManager.get_character_by_id(auth_info.main_char_id) + character = request.user.profile.main_character op.doctrine = form.cleaned_data['doctrine'] op.system = form.cleaned_data['system'] op.location = form.cleaned_data['location'] @@ -115,5 +105,5 @@ def edit_optimer(request, optimer_id): 'fc': op.fc, 'details': op.details, } - form = opForm(initial=data) + form = OpForm(initial=data) return render(request, 'registered/optimerupdate.html', context={'form': form}) diff --git a/permissions_tool/templates/permissions_tool/audit.html b/permissions_tool/templates/permissions_tool/audit.html index 076034cc..92c8756d 100644 --- a/permissions_tool/templates/permissions_tool/audit.html +++ b/permissions_tool/templates/permissions_tool/audit.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/permissions_tool/templates/permissions_tool/overview.html b/permissions_tool/templates/permissions_tool/overview.html index 8a31685a..76ece30e 100644 --- a/permissions_tool/templates/permissions_tool/overview.html +++ b/permissions_tool/templates/permissions_tool/overview.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/requirements.txt b/requirements.txt index 5ccdd5a0..0ce3bb88 100755 --- a/requirements.txt +++ b/requirements.txt @@ -16,6 +16,7 @@ django-bootstrap-form django-navhelper django-bootstrap-pagination django-redis>=4.4 +django-registration # awating release for fix to celery/django-celery#447 # django-celery diff --git a/run_alliance_corp_update.py b/run_alliance_corp_update.py deleted file mode 100644 index 938961d9..00000000 --- a/run_alliance_corp_update.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import unicode_literals -from eveonline.tasks import run_corp_update - -run_corp_update() -quit() diff --git a/services/hooks.py b/services/hooks.py index babef75e..0fd59535 100644 --- a/services/hooks.py +++ b/services/hooks.py @@ -1,11 +1,8 @@ from __future__ import unicode_literals from django.template.loader import render_to_string -from django.utils.safestring import mark_safe from alliance_auth.hooks import get_hooks -from authentication.states import MEMBER_STATE, BLUE_STATE -from authentication.models import AuthServicesInfo class ServicesHook: @@ -72,13 +69,12 @@ class ServicesHook: def service_active_for_user(self, user): pass - def show_service_ctrl(self, user, state): + def show_service_ctrl(self, user): """ Whether the service control should be displayed to the given user who has the given service state. Usually this function wont require overloading. :param user: django.contrib.auth.models.User - :param state: auth user state :return: bool True if the service should be shown """ return self.service_active_for_user(user) or user.is_superuser diff --git a/authentication/tests/__init__.py b/services/management/__init__.py similarity index 100% rename from authentication/tests/__init__.py rename to services/management/__init__.py diff --git a/eveonline/templatetags/__init__.py b/services/management/commands/__init__.py similarity index 100% rename from eveonline/templatetags/__init__.py rename to services/management/commands/__init__.py diff --git a/services/management/commands/verify_service_accounts.py b/services/management/commands/verify_service_accounts.py new file mode 100644 index 00000000..7855e605 --- /dev/null +++ b/services/management/commands/verify_service_accounts.py @@ -0,0 +1,12 @@ +from django.core.management.base import BaseCommand +from django.contrib.auth.models import User +from services.tasks import validate_services + + +class Command(BaseCommand): + help = "Ensures all service accounts belong to users with required permissions." + + def handle(self, *args, **options): + for u in User.objects.all(): + validate_services(u) + self.stdout.write(self.style.SUCCESS('Verified all user service accounts.')) diff --git a/services/managers/eve_api_manager.py b/services/managers/eve_api_manager.py deleted file mode 100644 index 98f4272f..00000000 --- a/services/managers/eve_api_manager.py +++ /dev/null @@ -1,353 +0,0 @@ -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 requests -try: - from urllib2 import HTTPError, URLError -except ImportError: # py3 - from urllib.error import URLError, HTTPError - -import logging - -logger = logging.getLogger(__name__) - - -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) - - class ApiServerUnreachableError(Exception): - def __init__(self, e): - self.error = e - - def __str__(self): - return 'Unable to reach API servers: %s' % str(self.error) - - @staticmethod - def get_characters_from_api(api_id, api_key): - logger.debug("Getting characters from api id %s" % api_id) - api = evelink.api.API(api_key=(api_id, api_key)) - # Should get characters - account = evelink.account.Account(api=api) - chars = account.characters() - logger.debug("Retrieved characters %s from api id %s" % (chars, api_id)) - return chars - - @staticmethod - def get_corporation_ticker_from_id(corp_id): - logger.debug("Getting ticker for corp id %s" % corp_id) - api = evelink.api.API() - corp = evelink.corp.Corp(api) - response = corp.corporation_sheet(corp_id) - logger.debug("Retrieved corp sheet for id %s: %s" % (corp_id, response)) - ticker = response[0]['ticker'] - logger.debug("Determined corp id %s ticker: %s" % (corp_id, ticker)) - return ticker - - @staticmethod - def get_alliance_information(alliance_id): - logger.debug("Getting info for alliance with id %s" % alliance_id) - api = evelink.api.API() - eve = evelink.eve.EVE(api=api) - alliance = eve.alliances() - results = alliance[0][int(alliance_id)] - logger.debug("Got alliance info %s" % results) - return results - - @staticmethod - def get_corporation_information(corp_id): - logger.debug("Getting info for corp with id %s" % corp_id) - api = evelink.api.API() - corp = evelink.corp.Corp(api=api) - corpinfo = corp.corporation_sheet(corp_id=int(corp_id)) - results = corpinfo[0] - 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) - api = evelink.api.API(api_key=(api_id, api_key)) - account = evelink.account.Account(api=api) - info = account.key_info() - logger.debug("API id %s is type %s" % (api_id, info[0]['type'])) - return info[0]['type'] == "account" - - @staticmethod - def check_api_is_full(api_id, api_key): - logger.debug("Checking if api id %s meets member requirements." % api_id) - api = evelink.api.API(api_key=(api_id, api_key)) - account = evelink.account.Account(api=api) - info = account.key_info() - logger.debug("API has mask %s, required is %s" % (info[0]['access_mask'], settings.MEMBER_API_MASK)) - return info[0]['access_mask'] & int(settings.MEMBER_API_MASK) == int(settings.MEMBER_API_MASK) - - @staticmethod - def check_blue_api_is_full(api_id, api_key): - logger.debug("Checking if api id %s meets blue requirements." % api_id) - api = evelink.api.API(api_key=(api_id, api_key)) - account = evelink.account.Account(api=api) - 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) - api = evelink.api.API(api_key=(api_id, api_key)) - account = evelink.account.Account(api=api) - info = account.key_info() - logger.debug("Got info for api id %s: %s" % (api_id, info)) - return info - - @staticmethod - def api_key_is_valid(api_id, api_key): - 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) - account.key_info() - logger.info("Verified api id %s is still valid." % api_id) - return True - - @staticmethod - def check_if_api_server_online(): - logger.debug("Checking if API server online.") - try: - api = evelink.api.API() - server = evelink.server.Server(api=api) - server.server_status() - logger.info("Verified API server is online and reachable.") - return True - except evelink.api.APIError: - logger.exception("APIError occured while trying to query api server. Possibly offline?") - - logger.warn("Unable to reach API server.") - return False - - @staticmethod - def check_if_id_is_corp(corp_id): - logger.debug("Checking if id %s is a corp." % corp_id) - try: - api = evelink.api.API() - corp = evelink.corp.Corp(api=api) - corpinfo = corp.corporation_sheet(corp_id=int(corp_id)) - assert corpinfo[0] - logger.debug("Confirmed id %s is a corp." % corp_id) - return True - except evelink.api.APIError as error: - if int(error.code) == '523': - logger.debug("Confirmed id %s is not a corp" % corp_id) - return False - logger.debug("APIError occured while checking if id %s is corp. Possibly not corp?" % corp_id) - - logger.debug("Unable to verify id %s is corp." % corp_id) - return False - - @staticmethod - def get_corp_standings(): - if settings.CORP_API_ID and settings.CORP_API_VCODE: - logger.debug("Getting corp standings with api id %s" % settings.CORP_API_ID) - api = evelink.api.API(api_key=(settings.CORP_API_ID, settings.CORP_API_VCODE)) - corp = evelink.corp.Corp(api=api) - corpinfo = corp.contacts() - results = corpinfo.result - logger.debug("Got corp standings from settings: %s" % results) - return results - else: - logger.debug("No corp API key supplied in settings. Unable to get standings.") - return {} - - @staticmethod - def get_corp_membertracking(api, vcode): - try: - logger.debug("Getting corp membertracking with api id %s" % settings.CORP_API_ID) - api = evelink.api.API(api_key=(api, vcode)) - corp = evelink.corp.Corp(api=api) - membertracking = corp.members() - results = membertracking.result - logger.debug("Got corp membertracking from settings: %s" % results) - return results - 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) - try: - api = evelink.api.API() - eve = evelink.eve.EVE(api=api) - alliance = eve.alliances() - results = alliance.result[int(alliance_id)] - if results: - logger.debug("Confirmed id %s is an alliance." % alliance_id) - return True - 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 - logger.debug("Unable to verify id %s is an an alliance." % alliance_id) - return False - - @staticmethod - def check_if_id_is_character(character_id): - logger.debug("Checking if id %s is a character." % character_id) - try: - api = evelink.api.API() - eve = evelink.eve.EVE(api=api) - results = eve.character_info_from_id(character_id) - if results: - logger.debug("Confirmed id %s is a character." % character_id) - return 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 - - @staticmethod - def check_if_alliance_exists(alliance_id): - logger.debug("Checking if alliance id %s exists." % alliance_id) - try: - api = evelink.api.API() - eve = evelink.eve.EVE(api=api) - alliances = eve.alliances() - if int(alliance_id) in alliances[0]: - logger.debug("Verified alliance id %s exists." % alliance_id) - return True - else: - logger.debug("Verified alliance id %s does not exist." % alliance_id) - return False - except evelink.api.APIError: - logger.exception("Unhandled APIError occured.") - return False - except ValueError: - # attempts to catch error resulting from checking alliance_of nonetype models - logger.exception("Unhandled ValueError occured. Possible nonetype alliance model.") - 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): - logger.debug("Checking if corp id %s exists." % corp_id) - try: - api = evelink.api.API() - 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'])) - return True - else: - logger.debug( - "Verified corp id %s has closed. Member count %s" % (corp_id, corpinfo[0]['members']['current'])) - return False - 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 - 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): - if settings.MEMBER_API_ACCOUNT: - 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 - return True - - @staticmethod - def validate_blue_api(api_id, api_key): - if settings.BLUE_API_ACCOUNT: - 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 blues - failed validation." % api_id) - return False - if EveApiManager.check_blue_api_is_full(api_id, api_key) is False: - 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 - except evelink.api.APIError as e: - if int(e.code) == 222: - raise EveApiManager.ApiInvalidError(api_id) - raise e - except (requests.exceptions.RequestException, HTTPError, URLError) as e: - raise EveApiManager.ApiServerUnreachableError(e) - auth = AuthServicesInfo.objects.get(user=user) - states = [auth.state] - from authentication.tasks import determine_membership_by_character # circular import issue - chars = info['characters'] - 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/migrations/0003_auto_20170322_2335.py b/services/migrations/0003_auto_20170322_2335.py new file mode 100644 index 00000000..ef58eaa8 --- /dev/null +++ b/services/migrations/0003_auto_20170322_2335.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-03-22 23:35 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('services', '0002_auto_20161016_0135'), + ] + + operations = [ + migrations.AlterField( + model_name='groupcache', + name='service', + field=models.CharField(choices=[('discourse', 'discourse'), ('discord', 'discord')], max_length=254, unique=True), + ), + ] diff --git a/services/modules/discord/auth_hooks.py b/services/modules/discord/auth_hooks.py index b123e868..7b034698 100644 --- a/services/modules/discord/auth_hooks.py +++ b/services/modules/discord/auth_hooks.py @@ -2,7 +2,6 @@ from __future__ import unicode_literals import logging -from django.conf import settings from django.template.loader import render_to_string from alliance_auth import hooks diff --git a/services/modules/discord/tasks.py b/services/modules/discord/tasks.py index 0e502d63..50a4a1ba 100644 --- a/services/modules/discord/tasks.py +++ b/services/modules/discord/tasks.py @@ -7,7 +7,6 @@ from django.conf import settings from django.contrib.auth.models import User from django.core.exceptions import ObjectDoesNotExist -from eveonline.managers import EveManager from notifications import notify from services.modules.discord.manager import DiscordOAuthManager from services.tasks import only_one @@ -60,6 +59,7 @@ class DiscordTasks: return True @staticmethod + @only_one @app.task(bind=True, name='discord.update_groups') def update_groups(task_self, pk): user = User.objects.get(pk=pk) @@ -98,18 +98,21 @@ class DiscordTasks: user = User.objects.get(pk=pk) logger.debug("Updating discord nickname for user %s" % user) if DiscordTasks.has_account(user): - character = EveManager.get_main_character(user) - logger.debug("Updating user %s discord nickname to %s" % (user, character.character_name)) - try: - DiscordOAuthManager.update_nickname(user.discord.uid, character.character_name) - except Exception as e: - if self: - logger.exception("Discord nickname sync failed for %s, retrying in 10 mins" % user) - raise self.retry(countdown=60 * 10) - else: - # Rethrow - raise e - logger.debug("Updated user %s discord nickname." % user) + if user.profile.main_character: + character = user.profile.main_character + logger.debug("Updating user %s discord nickname to %s" % (user, character.character_name)) + try: + DiscordOAuthManager.update_nickname(user.discord.uid, character.character_name) + except Exception as e: + if self: + logger.exception("Discord nickname sync failed for %s, retrying in 10 mins" % user) + raise self.retry(countdown=60 * 10) + else: + # Rethrow + raise e + logger.debug("Updated user %s discord nickname." % user) + else: + logger.debug("User %s does not have a main character" % user) else: logger.debug("User %s does not have a discord account" % user) diff --git a/services/modules/discourse/auth_hooks.py b/services/modules/discourse/auth_hooks.py index c8126676..cde66da4 100644 --- a/services/modules/discourse/auth_hooks.py +++ b/services/modules/discourse/auth_hooks.py @@ -46,7 +46,7 @@ class DiscourseService(ServicesHook): def render_services_ctrl(self, request): return render_to_string(self.service_ctrl_template, { - 'char': EveManager.get_main_character(request.user) + 'char': request.user.profile.main_character }, request=request) diff --git a/services/modules/discourse/views.py b/services/modules/discourse/views.py index cc44dab8..923b3c62 100644 --- a/services/modules/discourse/views.py +++ b/services/modules/discourse/views.py @@ -4,10 +4,6 @@ from django.conf import settings from django.contrib import messages from django.contrib.auth.decorators import login_required from django.shortcuts import render, redirect -from authentication.states import MEMBER_STATE, BLUE_STATE, NONE_STATE -from eveonline.models import EveCharacter -from eveonline.managers import EveManager -from authentication.models import AuthServicesInfo from .manager import DiscourseManager from .tasks import DiscourseTasks @@ -39,16 +35,15 @@ def discourse_sso(request): ## Check if user has access - auth = AuthServicesInfo.objects.get(user=request.user) if not request.user.has_perm(ACCESS_PERM): messages.error(request, 'You are not authorized to access Discourse.') return redirect('auth_dashboard') - if not auth.main_char_id: + if not request.user.profile.main_character: messages.error(request, "You must have a main character set to access Discourse.") return redirect('auth_characters') - main_char = EveManager.get_main_character(request.user) + main_char = request.user.profile.main_character if main_char is None: messages.error(request, "Your main character is missing a database model. Please select a new one.") return redirect('auth_characters') @@ -60,8 +55,7 @@ def discourse_sso(request): messages.error(request, 'No SSO payload or signature. Please contact support if this problem persists.') return redirect('auth_dashboard') - ## Validate the payload - + # Validate the payload try: payload = unquote(payload).encode('utf-8') decoded = base64.decodestring(payload).decode('utf-8') @@ -92,24 +86,23 @@ def discourse_sso(request): 'name': username, } - if auth.main_char_id: - params['avatar_url'] = 'https://image.eveonline.com/Character/%s_256.jpg' % auth.main_char_id + if main_char: + params['avatar_url'] = 'https://image.eveonline.com/Character/%s_256.jpg' % main_char.main_char_id return_payload = base64.encodestring(urlencode(params).encode('utf-8')) h = hmac.new(key, return_payload, digestmod=hashlib.sha256) query_string = urlencode({'sso': return_payload, 'sig': h.hexdigest()}) - ## Record activation and queue group sync - + # Record activation and queue group sync if not DiscourseTasks.has_account(request.user): discourse_user = DiscourseUser() discourse_user.user = request.user discourse_user.enabled = True discourse_user.save() - DiscourseTasks.update_groups.apply_async(args=[request.user.pk], countdown=30) # wait 30s for new user creation on Discourse - - ## Redirect back to Discourse + # wait 30s for new user creation on Discourse before triggering group sync + DiscourseTasks.update_groups.apply_async(args=[request.user.pk], countdown=30) + # Redirect back to Discourse url = '%s/session/sso_login' % settings.DISCOURSE_URL return redirect('%s?%s' % (url, query_string)) diff --git a/services/modules/ipboard/views.py b/services/modules/ipboard/views.py index 89d2550d..aa19f371 100644 --- a/services/modules/ipboard/views.py +++ b/services/modules/ipboard/views.py @@ -22,7 +22,7 @@ ACCESS_PERM = 'ipboard.access_ipboard' @permission_required(ACCESS_PERM) def activate_ipboard_forum(request): logger.debug("activate_ipboard_forum called by user %s" % request.user) - character = EveManager.get_main_character(request.user) + character = request.user.profile.main_character 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] != "": diff --git a/services/modules/ips4/views.py b/services/modules/ips4/views.py index 9117f932..e9076245 100644 --- a/services/modules/ips4/views.py +++ b/services/modules/ips4/views.py @@ -4,8 +4,6 @@ from django.contrib import messages from django.contrib.auth.decorators import login_required, permission_required from django.shortcuts import render, redirect -from authentication.decorators import members_and_blues -from eveonline.managers import EveManager from services.forms import ServicePasswordForm from .manager import Ips4Manager @@ -23,7 +21,7 @@ ACCESS_PERM = 'ips4.access_ips4' @permission_required(ACCESS_PERM) def activate_ips4(request): logger.debug("activate_ips4 called by user %s" % request.user) - character = EveManager.get_main_character(request.user) + character = request.user.profile.main_character 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 diff --git a/services/modules/market/views.py b/services/modules/market/views.py index 7c4b2248..e7caa879 100644 --- a/services/modules/market/views.py +++ b/services/modules/market/views.py @@ -22,7 +22,7 @@ ACCESS_PERM = 'market.access_market' @permission_required(ACCESS_PERM) def activate_market(request): logger.debug("activate_market called by user %s" % request.user) - character = EveManager.get_main_character(request.user) + character = request.user.profile.main_character if character is not None: 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, character.character_id, diff --git a/services/modules/mumble/views.py b/services/modules/mumble/views.py index cffda36d..5d2115be 100644 --- a/services/modules/mumble/views.py +++ b/services/modules/mumble/views.py @@ -3,16 +3,11 @@ from django.contrib.auth.decorators import login_required, permission_required from django.shortcuts import render, redirect from django.contrib import messages -from eveonline.managers import EveManager from eveonline.models import EveAllianceInfo -from authentication.states import MEMBER_STATE, BLUE_STATE, NONE_STATE -from authentication.models import AuthServicesInfo - from services.forms import ServicePasswordForm from .manager import MumbleManager from .tasks import MumbleTasks -from .models import MumbleUser import logging @@ -25,20 +20,11 @@ ACCESS_PERM = 'mumble.access_mumble' @permission_required(ACCESS_PERM) def activate_mumble(request): logger.debug("activate_mumble called by user %s" % request.user) - authinfo = AuthServicesInfo.objects.get(user=request.user) - character = EveManager.get_main_character(request.user) + character = request.user.profile.main_character ticker = character.corporation_ticker - 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(): - alliance = EveAllianceInfo.objects.filter(alliance_id=character.alliance_id)[0] - ticker = alliance.alliance_ticker - result = MumbleManager.create_user(request.user, ticker, character.character_name, blue=True) - else: - logger.debug("Adding mumble user for user %s with main character %s" % (request.user, character)) - result = MumbleManager.create_user(request.user, ticker, character.character_name) + logger.debug("Adding mumble user for %s with main character %s" % (request.user, character)) + result = MumbleManager.create_user(request.user, ticker, character.character_name) if result: logger.debug("Updated authserviceinfo for user %s with mumble credentials. Updating groups." % request.user) diff --git a/services/modules/openfire/views.py b/services/modules/openfire/views.py index bebb3309..29031ff7 100644 --- a/services/modules/openfire/views.py +++ b/services/modules/openfire/views.py @@ -4,12 +4,7 @@ from django.contrib import messages from django.contrib.auth.decorators import login_required, permission_required from django.contrib.auth.models import Group from django.shortcuts import render, redirect - -from authentication.decorators import members_and_blues -from eveonline.managers import EveManager -from eveonline.models import EveCharacter from services.forms import ServicePasswordForm - from .manager import OpenfireManager from .tasks import OpenfireTasks from .forms import JabberBroadcastForm @@ -28,7 +23,7 @@ ACCESS_PERM = 'openfire.access_openfire' @permission_required(ACCESS_PERM) def activate_jabber(request): logger.debug("activate_jabber called by user %s" % request.user) - character = EveManager.get_main_character(request.user) + character = request.user.profile.main_character 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 @@ -101,7 +96,7 @@ def jabber_broadcast_view(request): form.fields['group'].choices = allchoices logger.debug("Received POST request containing form, valid: %s" % form.is_valid()) if form.is_valid(): - main_char = EveManager.get_main_character(request.user) + main_char = request.user.profile.main_character logger.debug("Processing jabber broadcast for user %s with main character %s" % (request.user, main_char)) if main_char is not None: message_to_send = form.cleaned_data[ diff --git a/services/modules/phpbb3/auth_hooks.py b/services/modules/phpbb3/auth_hooks.py index 384e1e19..17c30f11 100644 --- a/services/modules/phpbb3/auth_hooks.py +++ b/services/modules/phpbb3/auth_hooks.py @@ -19,7 +19,7 @@ class Phpbb3Service(ServicesHook): ServicesHook.__init__(self) self.name = 'phpbb3' self.urlpatterns = urlpatterns - self.service_url = settings.FORUM_URL # TODO: This needs to be renamed at some point... + self.service_url = settings.PHPBB3_URL self.access_perm = 'phpbb3.access_phpbb3' @property diff --git a/services/modules/phpbb3/views.py b/services/modules/phpbb3/views.py index 34bc7963..39730d93 100644 --- a/services/modules/phpbb3/views.py +++ b/services/modules/phpbb3/views.py @@ -4,8 +4,6 @@ from django.contrib import messages from django.contrib.auth.decorators import login_required, permission_required from django.shortcuts import render, redirect -from authentication.decorators import members_and_blues -from eveonline.managers import EveManager from services.forms import ServicePasswordForm from .manager import Phpbb3Manager @@ -24,7 +22,7 @@ ACCESS_PERM = 'phpbb3.access_phpbb3' def activate_forum(request): logger.debug("activate_forum called by user %s" % request.user) # Valid now we get the main characters - character = EveManager.get_main_character(request.user) + character = request.user.profile.main_character 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'], character.character_id) @@ -66,7 +64,7 @@ def deactivate_forum(request): def reset_forum_password(request): logger.debug("reset_forum_password called by user %s" % request.user) if Phpbb3Tasks.has_account(request.user): - character = EveManager.get_main_character(request.user) + character = request.user.profile.main_character result = Phpbb3Manager.update_user_password(request.user.phpbb3.username, character.character_id) # false we failed if result != "": @@ -95,7 +93,7 @@ def set_forum_password(request): if form.is_valid() and Phpbb3Tasks.has_account(request.user): password = form.cleaned_data['password'] logger.debug("Form contains password of length %s" % len(password)) - character = EveManager.get_main_character(request.user) + character = request.user.profile.main_character result = Phpbb3Manager.update_user_password(request.user.phpbb3.username, character.character_id, password=password) if result != "": diff --git a/services/modules/seat/views.py b/services/modules/seat/views.py index 6a1e6a51..ee4e0fee 100644 --- a/services/modules/seat/views.py +++ b/services/modules/seat/views.py @@ -21,8 +21,7 @@ ACCESS_PERM = 'seat.access_seat' @permission_required(ACCESS_PERM) def activate_seat(request): logger.debug("activate_seat called by user %s" % request.user) - # Valid now we get the main characters - character = EveManager.get_main_character(request.user) + character = request.user.profile.main_character logger.debug("Checking SeAT for inactive users with the same username") stat = SeatManager.check_user_status(character.character_name) if stat == {}: diff --git a/services/modules/smf/views.py b/services/modules/smf/views.py index a5ce14e5..f2227773 100644 --- a/services/modules/smf/views.py +++ b/services/modules/smf/views.py @@ -23,7 +23,7 @@ ACCESS_PERM = 'smf.access_smf' def activate_smf(request): logger.debug("activate_smf called by user %s" % request.user) # Valid now we get the main characters - character = EveManager.get_main_character(request.user) + character = request.user.profile.main_character 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'], character.character_id) # if empty we failed @@ -64,7 +64,7 @@ def deactivate_smf(request): @permission_required(ACCESS_PERM) def reset_smf_password(request): logger.debug("reset_smf_password called by user %s" % request.user) - character = EveManager.get_main_character(request.user) + character = request.user.profile.main_character if SmfTasks.has_account(request.user) and character is not None: result = SmfManager.update_user_password(request.user.smf.username, character.character_id) # false we failed @@ -90,7 +90,7 @@ def set_smf_password(request): logger.debug("Received POST request with form.") form = ServicePasswordForm(request.POST) logger.debug("Form is valid: %s" % form.is_valid()) - character = EveManager.get_main_character(request.user) + character = request.user.profile.main_character if form.is_valid() and SmfTasks.has_account(request.user) and character is not None: password = form.cleaned_data['password'] logger.debug("Form contains password of length %s" % len(password)) diff --git a/services/modules/teamspeak3/manager.py b/services/modules/teamspeak3/manager.py index 5661b62f..1aa35d5f 100755 --- a/services/modules/teamspeak3/manager.py +++ b/services/modules/teamspeak3/manager.py @@ -33,11 +33,6 @@ class Teamspeak3Manager: sanatized = "[" + corp_ticker + "]" + username return sanatized[:30] - @staticmethod - def __generate_username_blue(username, corp_ticker): - sanatized = "[BLUE][" + corp_ticker + "]" + username - return sanatized[:30] - @staticmethod def _get_userid(uid): logger.debug("Looking for uid %s on TS3 server." % uid) @@ -210,34 +205,6 @@ class Teamspeak3Manager: logger.exception("Failed to add teamspeak user %s - received response: %s" % (username_clean, ret)) return "", "" - @staticmethod - def add_blue_user(username, corp_ticker): - username_clean = Teamspeak3Manager.__santatize_username(Teamspeak3Manager.__generate_username_blue(username, - corp_ticker)) - server = Teamspeak3Manager.__get_created_server() - logger.debug("Adding user to TS3 server with cleaned username %s" % username_clean) - server_groups = Teamspeak3Manager._group_list() - 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) - - 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'] - logger.info("Created permission token for blue user %s on TS3 server" % username_clean) - return username_clean, token - except: - logger.exception("Failed to add blue teamspeak user %s - received response: %s" % (username_clean, ret)) - return "", "" - @staticmethod def delete_user(uid): server = Teamspeak3Manager.__get_created_server() diff --git a/services/modules/teamspeak3/tasks.py b/services/modules/teamspeak3/tasks.py index 4643449f..f706fcb7 100644 --- a/services/modules/teamspeak3/tasks.py +++ b/services/modules/teamspeak3/tasks.py @@ -3,13 +3,10 @@ from __future__ import unicode_literals import logging from alliance_auth.celeryapp import app -from celery.schedules import crontab -from django.conf import settings from django.contrib.auth.models import User from django.core.exceptions import ObjectDoesNotExist from notifications import notify -from authentication.models import AuthServicesInfo from .util.ts3 import TeamspeakError from .manager import Teamspeak3Manager from .models import AuthTS, TSgroup, UserTSgroup, Teamspeak3User diff --git a/services/modules/teamspeak3/views.py b/services/modules/teamspeak3/views.py index 4eee0799..ff882a4c 100644 --- a/services/modules/teamspeak3/views.py +++ b/services/modules/teamspeak3/views.py @@ -4,11 +4,6 @@ from django.contrib import messages from django.contrib.auth.decorators import login_required, permission_required from django.shortcuts import render, redirect -from authentication.states import BLUE_STATE -from authentication.models import AuthServicesInfo -from eveonline.managers import EveManager -from eveonline.models import EveAllianceInfo - from services.modules.teamspeak3.manager import Teamspeak3Manager from .forms import TeamspeakJoinForm @@ -25,20 +20,11 @@ ACCESS_PERM = 'teamspeak3.access_teamspeak3' def activate_teamspeak3(request): logger.debug("activate_teamspeak3 called by user %s" % request.user) - authinfo = AuthServicesInfo.objects.get(user=request.user) - character = EveManager.get_main_character(request.user) + character = request.user.profile.main_character ticker = character.corporation_ticker - 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(): - alliance = EveAllianceInfo.objects.filter(alliance_id=character.alliance_id)[0] - ticker = alliance.alliance_ticker - result = Teamspeak3Manager.add_blue_user(character.character_name, ticker) - else: - logger.debug("Adding TS3 user for user %s with main character %s" % (request.user, character)) - result = Teamspeak3Manager.add_user(character.character_name, ticker) + logger.debug("Adding TS3 user for user %s with main character %s" % (request.user, character)) + result = Teamspeak3Manager.add_user(character.character_name, ticker) # if its empty we failed if result[0] is not "": @@ -93,20 +79,12 @@ def reset_teamspeak3_perm(request): logger.debug("reset_teamspeak3_perm called by user %s" % request.user) if not Teamspeak3Tasks.has_account(request.user): return redirect("auth_services") - authinfo = AuthServicesInfo.objects.get(user=request.user) - character = EveManager.get_main_character(request.user) + character = request.user.profile.main_character logger.debug("Deleting TS3 user for user %s" % request.user) Teamspeak3Manager.delete_user(request.user.teamspeak3.uid) - 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(request.user.teamspeak3.uid, - character.character_name, - character.corporation_ticker) - else: - logger.debug("Generating new permission key for user %s with main character %s" % (request.user, character)) - result = Teamspeak3Manager.generate_new_permissionkey(request.user.teamspeak3.uid, character.character_name, + logger.debug("Generating new permission key for user %s with main character %s" % (request.user, character)) + result = Teamspeak3Manager.generate_new_permissionkey(request.user.teamspeak3.uid, character.character_name, character.corporation_ticker) # if blank we failed diff --git a/services/modules/xenforo/views.py b/services/modules/xenforo/views.py index 0e8587e5..e3f4c620 100644 --- a/services/modules/xenforo/views.py +++ b/services/modules/xenforo/views.py @@ -21,7 +21,7 @@ ACCESS_PERM = 'xenforo.access_xenforo' @permission_required(ACCESS_PERM) def activate_xenforo_forum(request): logger.debug("activate_xenforo_forum called by user %s" % request.user) - character = EveManager.get_main_character(request.user) + character = request.user.profile.main_character 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 diff --git a/services/signals.py b/services/signals.py index 69512573..2c76d466 100644 --- a/services/signals.py +++ b/services/signals.py @@ -10,10 +10,7 @@ from django.db.models.signals import pre_save from django.dispatch import receiver from services.hooks import ServicesHook -from alliance_auth.hooks import get_hooks -from authentication.tasks import disable_user -from authentication.tasks import disable_member -from authentication.tasks import set_state +from services.tasks import disable_user logger = logging.getLogger(__name__) @@ -109,8 +106,5 @@ def pre_save_user(sender, instance, *args, **kwargs): if old_instance.is_active and not instance.is_active: logger.info("Disabling services for inactivation of user %s" % instance) disable_user(instance) - elif instance.is_active and not old_instance.is_active: - logger.info("Assessing state of reactivated user %s" % instance) - set_state(instance) except User.DoesNotExist: pass diff --git a/services/tasks.py b/services/tasks.py index ac0f8896..138dbe84 100644 --- a/services/tasks.py +++ b/services/tasks.py @@ -48,3 +48,11 @@ def validate_services(self, user): svc.validate_user(user) except: logger.exception('Exception running validate_user for services module %s on user %s' % (svc, user)) + + +def disable_user(user): + logger.debug('Disabling all services for user %s' % user) + for svc in ServicesHook.get_services(): + if svc.service_active_for_user(user): + svc.delete_user(user) + diff --git a/services/views.py b/services/views.py index a5517341..2035787f 100755 --- a/services/views.py +++ b/services/views.py @@ -6,8 +6,6 @@ from django.shortcuts import render from django.utils.translation import ugettext_lazy as _ from alliance_auth.hooks import get_hooks -from authentication.decorators import members_and_blues -from authentication.models import AuthServicesInfo from eveonline.models import EveCharacter from services.forms import FleetFormatterForm @@ -49,19 +47,12 @@ def fleet_formatter_view(request): @login_required def services_view(request): logger.debug("services_view called by user %s" % request.user) - auth = AuthServicesInfo.objects.get(user=request.user) - char = None - if auth.main_char_id: - try: - char = EveCharacter.objects.get(character_id=auth.main_char_id) - except EveCharacter.DoesNotExist: - messages.warning(request, _("There's a problem with your main character. Please select a new one.")) - + char = request.profile.main_character context = {'service_ctrls': []} for fn in get_hooks('services_hook'): # Render hooked services controls svc = fn() - if svc.show_service_ctrl(request.user, auth.state): + if svc.show_service_ctrl(request.user): context['service_ctrls'].append(svc.render_services_ctrl(request)) return render(request, 'registered/services.html', context=context) diff --git a/services/managers/srp_manager.py b/srp/managers.py similarity index 95% rename from services/managers/srp_manager.py rename to srp/managers.py index a71c3ca2..dddccf84 100644 --- a/services/managers/srp_manager.py +++ b/srp/managers.py @@ -1,36 +1,36 @@ -from __future__ import unicode_literals -from django.conf import settings - -import requests -import logging - -logger = logging.getLogger(__name__) - - -class srpManager: - def __init__(self): - pass - - @staticmethod - 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): - url = ("https://www.zkillboard.com/api/killID/%s/" % kill_id) - 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 - else: - raise ValueError("Invalid Kill ID") +from __future__ import unicode_literals +from django.conf import settings + +import requests +import logging + +logger = logging.getLogger(__name__) + + +class SRPManager: + def __init__(self): + pass + + @staticmethod + 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): + url = ("https://www.zkillboard.com/api/killID/%s/" % kill_id) + 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 + else: + raise ValueError("Invalid Kill ID") diff --git a/srp/migrations/0003_auto_20170322_2335.py b/srp/migrations/0003_auto_20170322_2335.py new file mode 100644 index 00000000..0b644048 --- /dev/null +++ b/srp/migrations/0003_auto_20170322_2335.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-03-22 23:35 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('srp', '0002_srpuserrequest_srp_status_choices'), + ] + + operations = [ + migrations.AlterModelOptions( + name='srpfleetmain', + options={'permissions': (('access_srp', 'Can access SRP module'),)}, + ), + migrations.AlterField( + model_name='srpfleetmain', + name='fleet_doctrine', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='srpfleetmain', + name='fleet_name', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='srpfleetmain', + name='fleet_srp_aar_link', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='srpfleetmain', + name='fleet_srp_code', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='srpfleetmain', + name='fleet_srp_status', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='srpuserrequest', + name='additional_info', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='srpuserrequest', + name='after_action_report_link', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='srpuserrequest', + name='killboard_link', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='srpuserrequest', + name='srp_ship_name', + field=models.CharField(default='', max_length=254), + ), + ] diff --git a/srp/models.py b/srp/models.py index 65b4836b..836ad27e 100755 --- a/srp/models.py +++ b/srp/models.py @@ -26,6 +26,9 @@ class SrpFleetMain(models.Model): def pending_requests(self): return self.srpuserrequest_set.filter(srp_status='Pending').count() + class Meta: + permissions = (('access_srp', 'Can access SRP module'),) + @python_2_unicode_compatible class SrpUserRequest(models.Model): diff --git a/srp/views.py b/srp/views.py index 775a7f96..c4b41544 100755 --- a/srp/views.py +++ b/srp/views.py @@ -1,21 +1,19 @@ from __future__ import unicode_literals -from django.shortcuts import render, redirect +from django.shortcuts import render, redirect, get_object_or_404 from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import permission_required from django.contrib import messages from eveonline.managers import EveManager -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 srp.managers import SRPManager from notifications import notify from django.utils import timezone from django.utils.translation import ugettext_lazy as _ -from authentication.decorators import members_and_blues import uuid import logging @@ -32,7 +30,7 @@ def random_string(string_length=10): @login_required -@members_and_blues() +@permission_required('srp.access_srp') def srp_management(request): logger.debug("srp_management called by user %s" % request.user) fleets = SrpFleetMain.objects.filter(fleet_srp_status="") @@ -42,7 +40,7 @@ def srp_management(request): @login_required -@members_and_blues() +@permission_required('srp.access_srp') def srp_management_all(request): logger.debug("srp_management_all called by user %s" % request.user) fleets = SrpFleetMain.objects.all() @@ -52,20 +50,15 @@ def srp_management_all(request): @login_required -@members_and_blues() +@permission_required('srp.access_srp') 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(): - fleet_main = SrpFleetMain.objects.get(id=fleet_id) - context = {"fleet_id": fleet_id, "fleet_status": fleet_main.fleet_srp_status, - "srpfleetrequests": fleet_main.srpuserrequest_set.all(), - "totalcost": fleet_main.total_cost} + fleet_main = get_object_or_404(SrpFleetMain, id=fleet_id) + context = {"fleet_id": fleet_id, "fleet_status": fleet_main.fleet_srp_status, + "srpfleetrequests": fleet_main.srpuserrequest_set.all(), + "totalcost": fleet_main.total_cost} - 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 redirect("auth_srp_management_view") + return render(request, 'registered/srpfleetdata.html', context=context) @login_required @@ -79,15 +72,12 @@ 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 = AuthServicesInfo.objects.get(user=request.user) - character = EveManager.get_character_by_id(authinfo.main_char_id) - srp_fleet_main = SrpFleetMain() srp_fleet_main.fleet_name = form.cleaned_data['fleet_name'] srp_fleet_main.fleet_doctrine = form.cleaned_data['fleet_doctrine'] srp_fleet_main.fleet_time = form.cleaned_data['fleet_time'] srp_fleet_main.fleet_srp_code = random_string(8) - srp_fleet_main.fleet_commander = character + srp_fleet_main.fleet_commander = request.user.profile.main_character srp_fleet_main.save() @@ -109,15 +99,10 @@ def srp_fleet_add_view(request): @permission_required('auth.srp_management') def srp_fleet_remove(request, fleet_id): logger.debug("srp_fleet_remove called by user %s for fleet id %s" % (request.user, fleet_id)) - if SrpFleetMain.objects.filter(id=fleet_id).exists(): - 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 %(fleetname)s.') % {"fleetname": 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)) - messages.error(request, _('Unable to locate SRP fleet with ID %(fleetid)s') % {"fleetid": fleet_id}) + srpfleetmain = get_object_or_404(SrpFleetMain, 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 %(fleetname)s.') % {"fleetname": srpfleetmain.fleet_name}) return redirect("auth_srp_management_view") @@ -125,16 +110,11 @@ def srp_fleet_remove(request, fleet_id): @permission_required('auth.srp_management') def srp_fleet_disable(request, fleet_id): logger.debug("srp_fleet_disable called by user %s for fleet id %s" % (request.user, fleet_id)) - if SrpFleetMain.objects.filter(id=fleet_id).exists(): - srpfleetmain = SrpFleetMain.objects.get(id=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 %(fleetname)s.') % {"fleetname": 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)) - messages.error(request, _('Unable to locate SRP fleet with ID %(fleetid)s') % {"fleetid": fleet_id}) + srpfleetmain = get_object_or_404(SrpFleetMain, id=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 %(fleetname)s.') % {"fleetname": srpfleetmain.fleet_name}) return redirect("auth_srp_management_view") @@ -142,16 +122,11 @@ def srp_fleet_disable(request, fleet_id): @permission_required('auth.srp_management') def srp_fleet_enable(request, fleet_id): logger.debug("srp_fleet_enable called by user %s for fleet id %s" % (request.user, fleet_id)) - if SrpFleetMain.objects.filter(id=fleet_id).exists(): - srpfleetmain = SrpFleetMain.objects.get(id=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 %(fleetname)s.') % {"fleetname": 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)) - messages.error(request, _('Unable to locate SRP fleet with ID %(fleetid)s') % {"fleetid": fleet_id}) + srpfleetmain = get_object_or_404(SrpFleetMain, id=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 %(fleetname)s.') % {"fleetname": srpfleetmain.fleet_name}) return redirect("auth_srp_management_view") @@ -159,16 +134,11 @@ def srp_fleet_enable(request, fleet_id): @permission_required('auth.srp_management') def srp_fleet_mark_completed(request, fleet_id): logger.debug("srp_fleet_mark_completed called by user %s for fleet id %s" % (request.user, fleet_id)) - if SrpFleetMain.objects.filter(id=fleet_id).exists(): - srpfleetmain = SrpFleetMain.objects.get(id=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 %(fleetname)s as completed.') % {"fleetname": 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)) - messages.error(request, _('Unable to locate SRP fleet with ID %(fleetid)s') % {"fleetid": fleet_id}) + srpfleetmain = get_object_or_404(SrpFleetMain, id=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 %(fleetname)s as completed.') % {"fleetname": srpfleetmain.fleet_name}) return redirect("auth_srp_fleet_view", fleet_id) @@ -176,22 +146,16 @@ def srp_fleet_mark_completed(request, fleet_id): @permission_required('auth.srp_management') def srp_fleet_mark_uncompleted(request, fleet_id): logger.debug("srp_fleet_mark_uncompleted called by user %s for fleet id %s" % (request.user, fleet_id)) - if SrpFleetMain.objects.filter(id=fleet_id).exists(): - srpfleetmain = SrpFleetMain.objects.get(id=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 %(fleetname)s as incomplete.') % {"fleetname": 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)) - messages.error(request, _('Unable to locate SRP fleet with ID %(fleetid)s') % {"fleetid": fleet_id}) - return redirect('auth_srp_management_view') + srpfleetmain = get_object_or_404(SrpFleetMain, id=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 %(fleetname)s as incomplete.') % {"fleetname": srpfleetmain.fleet_name}) + return redirect("auth_srp_fleet_view", fleet_id) @login_required -@members_and_blues() +@permission_required('srp.access_srp') 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 @@ -206,8 +170,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 = AuthServicesInfo.objects.get(user=request.user) - character = EveManager.get_character_by_id(authinfo.main_char_id) + character = request.user.profile.main_character srp_fleet_main = SrpFleetMain.objects.get(fleet_srp_code=fleet_srp) post_time = timezone.now() @@ -218,8 +181,8 @@ def srp_request_view(request, fleet_srp): srp_request.srp_fleet_main = srp_fleet_main try: - srp_kill_link = srpManager.get_kill_id(srp_request.killboard_link) - (ship_type_id, ship_value) = srpManager.get_kill_data(srp_kill_link) + srp_kill_link = SRPManager.get_kill_id(srp_request.killboard_link) + (ship_type_id, 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)) @@ -251,87 +214,57 @@ def srp_request_view(request, fleet_srp): @permission_required('auth.srp_management') def srp_request_remove(request, srp_request_id): logger.debug("srp_request_remove 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 - srpuserrequest.delete() - logger.info("Deleted SRP request id %s for user %s" % (srp_request_id, request.user)) - messages.success(request, _('Deleted SRP request from %(character)s for their %(ship)s.') % { + srpuserrequest = get_object_or_404(SrpUserRequest, id=srp_request_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 %(character)s for their %(ship)s.') % { "character": srpuserrequest.character, "ship": 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)) - messages.error(request, _('Unable to locate SRP request with ID %(requestid)s') % {"requestid": srp_request_id}) - return redirect("auth_srp_management_view") - else: - return redirect("auth_srp_fleet_view", stored_fleet_view) + return redirect("auth_srp_fleet_view", srpuserrequest.srp_fleet_main.id) @login_required @permission_required('auth.srp_management') 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 - srpuserrequest.srp_status = "Approved" - 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)) - messages.success(request, _('Approved SRP request from %(character)s for their %(ship)s.') % { - "character": srpuserrequest.character, "ship": 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)) - messages.error(request, _('Unable to locate SRP request with ID %(requestid)s') % {"requestid": srp_request_id}) - return redirect("auth_srp_management_view") - else: - return redirect("auth_srp_fleet_view", stored_fleet_view) + srpuserrequest = get_object_or_404(SrpUserRequest, id=srp_request_id) + srpuserrequest.srp_status = "Approved" + 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)) + messages.success(request, _('Approved SRP request from %(character)s for their %(ship)s.') % { + "character": srpuserrequest.character, "ship": 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) + ) + return redirect("auth_srp_fleet_view", srpuserrequest.srp_fleet_main.id) @login_required @permission_required('auth.srp_management') def srp_request_reject(request, srp_request_id): logger.debug("srp_request_reject 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 - 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)) - messages.success(request, _('Rejected SRP request from %(character)s for their %(ship)s.') % { - "character": srpuserrequest.character, "ship": 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)) - messages.error(request, _('Unable to locate SRP request with ID %(requestid)s') % {"requestid": srp_request_id}) - return redirect("auth_srp_management_view") - else: - return redirect("auth_srp_fleet_view", stored_fleet_view) + srpuserrequest = get_object_or_404(SrpUserRequest, id=srp_request_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)) + messages.success(request, _('Rejected SRP request from %(character)s for their %(ship)s.') % { + "character": srpuserrequest.character, "ship": 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) + ) + return redirect("auth_srp_fleet_view", srpuserrequest.srp_fleet_main.id) @login_required @@ -340,16 +273,11 @@ 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)) - 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)) - messages.error(request, _('Unable to locate SRP request with ID %(requestid)s') % {"requestid": fleet_srp_request_id}) - return redirect("auth_srp_management_view") - + srp_request = get_object_or_404(SrpUserRequest, id=fleet_srp_request_id) if request.method == 'POST': form = SrpFleetUpdateCostForm(request.POST) logger.debug("Request type POST contains form valid: %s" % form.is_valid()) if form.is_valid(): - 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" % ( @@ -369,26 +297,17 @@ def srp_request_update_amount_view(request, fleet_srp_request_id): @permission_required('auth.srp_management') 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 - if SrpFleetMain.objects.filter(id=fleet_id).exists(): - if request.method == 'POST': - form = SrpFleetMainUpdateForm(request.POST) - logger.debug("Request type POST contains form valid: %s" % form.is_valid()) - if form.is_valid(): - srpfleetmain = SrpFleetMain.objects.get(id=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)) - messages.success(request, _('Saved changes to SRP fleet %(fleetname)s') % {"fleetname": 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) - + srpfleetmain = get_object_or_404(SrpFleetMain, id=fleet_id) + if request.method == 'POST': + form = SrpFleetMainUpdateForm(request.POST) + logger.debug("Request type POST contains form valid: %s" % form.is_valid()) + if form.is_valid(): + 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)) + messages.success(request, _('Saved changes to SRP fleet %(fleetname)s') % {"fleetname": srpfleetmain.fleet_name}) + return redirect("auth_srp_management_view") else: - 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 %(fleetid)s') % {"fleetid": fleet_id}) - return redirect("auth_srp_management_view") + logger.debug("Returning blank SrpFleetMainUpdateForm") + form = SrpFleetMainUpdateForm() + return render(request, 'registered/srpfleetupdate.html', context={'form': form}) \ No newline at end of file diff --git a/stock/templates/public/index.html b/stock/templates/public/index.html deleted file mode 100644 index 1a7fa810..00000000 --- a/stock/templates/public/index.html +++ /dev/null @@ -1,74 +0,0 @@ -{% load staticfiles %} - - - - - {{ SITE_NAME }} - - - - -
    -

    - - Auth - -

    - {% if FORUM_URL %} -

    - - Forums - -

    - {% endif %} - {% if KILLBOARD_URL %} -

    - - Killboard - -

    - {% endif %} - {% if EXTERNAL_MEDIA_URL %} -

    - - External Media - -

    - {% endif %} -
    - - diff --git a/stock/templates/public/login.html b/stock/templates/public/login.html deleted file mode 100644 index dc8366aa..00000000 --- a/stock/templates/public/login.html +++ /dev/null @@ -1,101 +0,0 @@ -{% load staticfiles %} -{% load bootstrap %} -{% load i18n %} - - - - - - - - - - - {{ SITE_NAME }} - {% trans "Login" %} - - {% include 'bundles/bootstrap-css.html' %} - {% include 'bundles/fontawesome.html' %} - - - -
    -
    - {% if messages %} - {% for message in messages %} -
    {{ message }}
    - {% endfor %} - {% endif %} -
    -
    - - -
    -
    -

    - - - -

    -
    -
    -
    - - -
    -
    -{% include 'bundles/bootstrap-js.html' %} - - diff --git a/stock/templates/public/register.html b/stock/templates/public/register.html deleted file mode 100644 index 147fa989..00000000 --- a/stock/templates/public/register.html +++ /dev/null @@ -1,78 +0,0 @@ -{% load staticfiles %} -{% load bootstrap %} -{% load i18n %} - - - - - - - - - - {{ SITE_NAME }} - {% trans "Registration" %} - - {% include 'bundles/bootstrap-css.html' %} - {% include 'bundles/fontawesome.html' %} - - - - -
    -
    -
    -
    - {% if error %} - - {% endif %} -
    - {% csrf_token %} - - {{ form|bootstrap }} - -
    -
    -
    - - -
    -
    -{% include 'bundles/bootstrap-js.html' %} - - diff --git a/stock/templates/registered/addapikey.html b/stock/templates/registered/addapikey.html deleted file mode 100644 index a0f9c9bc..00000000 --- a/stock/templates/registered/addapikey.html +++ /dev/null @@ -1,54 +0,0 @@ -{% extends "public/base.html" %} -{% load bootstrap %} -{% load staticfiles %} -{% load i18n %} - -{% block title %}Alliance Auth{% endblock %} - -{% block page_title %}Add Api Key{% endblock page_title %} -{% block extra_css %}{% endblock extra_css %} - -{% block content %} -
    -

    {% trans "Add Api Key" %}

    - -
    -
    -
    -

    - {% blocktrans %}Member API keys require access mask {{MEMBER_API_MASK}} or greater for services.{% endblocktrans %} -

    - {% if MEMBER_API_ACCOUNT %} -

    - {% trans "Member API keys need to be account-wide." %} -

    - {% endif %} -

    - {% trans "Create a full API key" %} -

    -

    - {% blocktrans %}Blue API keys require access mask {{BLUE_API_MASK}} or greater for services.{% endblocktrans %} -

    - {% if BLUE_API_ACCOUNT %} -

    - {% trans "BLUE API keys need to be account-wide." %} -

    - {% endif %} -

    - {% trans "Create a blue key" %} -

    - - -
    -
    -
    -
    - -{% endblock content %} diff --git a/stock/templates/registered/addoperation.html b/stock/templates/registered/addoperation.html index 88116a5a..5b8d264c 100644 --- a/stock/templates/registered/addoperation.html +++ b/stock/templates/registered/addoperation.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/addtimer.html b/stock/templates/registered/addtimer.html index 11b1c2e3..3fa060e3 100755 --- a/stock/templates/registered/addtimer.html +++ b/stock/templates/registered/addtimer.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/apisso.html b/stock/templates/registered/apisso.html deleted file mode 100644 index 4b219d21..00000000 --- a/stock/templates/registered/apisso.html +++ /dev/null @@ -1,22 +0,0 @@ -{% extends 'public/base.html' %} -{% load staticfiles %} -{% load i18n %} -{% block title %}{% trans "Verify API Ownership" %}{% endblock %} -{% block page_title%}{% trans "Verify API Ownership" %}{% endblock %} -{% block content %} -
    -

    {% trans "Verify API Ownership" %}

    -
    -
    {% blocktrans %}Please authenticate as a character on API {{ api.api_id }} to prove ownership.{% endblocktrans %}
    -
    -
    - - - -
    -
    -
    - - -{% endblock %} diff --git a/stock/templates/registered/characters.html b/stock/templates/registered/characters.html deleted file mode 100755 index a6e20abc..00000000 --- a/stock/templates/registered/characters.html +++ /dev/null @@ -1,66 +0,0 @@ -{% extends "public/base.html" %} -{% load staticfiles %} -{% load i18n %} - -{% block title %}Alliance Auth{% endblock %} - -{% block page_title %}{% trans "Characters" %}{% endblock page_title %} -{% block extra_css %}{% endblock extra_css %} - -{% block content %} -
    -

    {% trans "Characters" %}

    - -
    - - {% if authinfo.main_char_id %} - {% else %} - - {% endif %} -
    - {% for character in characters %} -
    - -
    - - -
    -
    - -
    - -
    -

    {% trans "Alliance: " %} {{ character.alliance_name }}

    - -

    {% trans "Corporation: " %}{{ character.corporation_name }}

    - -

    {% trans "Corporation Ticker: " %} {{ character.corporation_ticker }}

    -
    -
    -
    -
    - {% endfor %} -
    -
    -
    - -{% endblock content %} diff --git a/stock/templates/registered/dashboard.html b/stock/templates/registered/dashboard.html deleted file mode 100644 index 815fee83..00000000 --- a/stock/templates/registered/dashboard.html +++ /dev/null @@ -1,121 +0,0 @@ -{% extends "public/base.html" %} -{% load staticfiles %} -{% load i18n %} - -{% block title %}{% trans "Dashboard" %}{% endblock %} - -{% block content %} -
    -

    {% trans "Dashboard" %}

    -
    -
    -
    -
    -
    {% trans "Main Character" %}
    -
    - {% if main %} -
    - - - -
    {{ main.character_name }}
    -
    -
    - - - -
    {{ main.corporation_name }}
    -
    -
    - {% if main.alliance_id %} - - - -
    {{ main.alliance_name }}
    - {% endif %} -
    - {% else %} - - {% endif %} -
    - - -
    -
    -
    -
    -
    -
    {% trans "Groups" %}
    -
    -
    - - {% for group in user.groups.all %} - - - - {% endfor %} -
    {{ group.name }}
    -
    -
    -
    -
    -
    - {% if apis %} - {% for api in apis %} -
    -
    -
    - {% trans "API ID" %} {{ api.id }} -
    -
    - - - {% if api_sso_validation and not api.sso_verified %} - - - - {% endif %} -
    -
    - - - - - - - - {% for char in api.characters %} - - - - - - - {% endfor %} - {% if api.corp %} - - - - - - - {% endif %} -
    {% trans "Name" %}{% trans "Corp" %}{% trans "Alliance" %}
    - - {{ char.character_name }}{{ char.corporation_name }}{{ char.alliance_name }}
    - - {{ api.corporation_name }}{{ api.alliance_name }}
    -
    - {% endfor %} - {% else %} - - {% endif %} -
    -
    -
    -{% endblock %} diff --git a/stock/templates/registered/fleetformattertool.html b/stock/templates/registered/fleetformattertool.html index 74ae3bc9..bc34c664 100644 --- a/stock/templates/registered/fleetformattertool.html +++ b/stock/templates/registered/fleetformattertool.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/fleetup.html b/stock/templates/registered/fleetup.html index db1f067f..008fa374 100644 --- a/stock/templates/registered/fleetup.html +++ b/stock/templates/registered/fleetup.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} @@ -110,7 +110,7 @@ {% endfor %} {% else %} -

    {% trans "There seems to be no Operations in the near future, go make ISK!" %}

    +

    {% trans "There seems to be no Operations in the near future." %}

    {% endif %}
    @@ -192,7 +192,7 @@
    {% else %} -

    {% trans "There seems to be no Timers in the near future, this does not mean there isn't any!" %}

    +

    {% trans "There seems to be no Timers in the near future." %}

    {% endif %} diff --git a/stock/templates/registered/fleetupcharacters.html b/stock/templates/registered/fleetupcharacters.html index 925c9421..77edb296 100644 --- a/stock/templates/registered/fleetupcharacters.html +++ b/stock/templates/registered/fleetupcharacters.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/fleetupdoctrine.html b/stock/templates/registered/fleetupdoctrine.html index 3a5bc194..e395e1eb 100644 --- a/stock/templates/registered/fleetupdoctrine.html +++ b/stock/templates/registered/fleetupdoctrine.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/fleetupdoctrinesview.html b/stock/templates/registered/fleetupdoctrinesview.html index 7899eacc..d532425a 100644 --- a/stock/templates/registered/fleetupdoctrinesview.html +++ b/stock/templates/registered/fleetupdoctrinesview.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/fleetupfitting.html b/stock/templates/registered/fleetupfitting.html index ea696664..1bce0800 100644 --- a/stock/templates/registered/fleetupfitting.html +++ b/stock/templates/registered/fleetupfitting.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/fleetupfittingsview.html b/stock/templates/registered/fleetupfittingsview.html index 0ad75699..31cabcca 100644 --- a/stock/templates/registered/fleetupfittingsview.html +++ b/stock/templates/registered/fleetupfittingsview.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/groupmanagement.html b/stock/templates/registered/groupmanagement.html index 42e622ff..688987d8 100644 --- a/stock/templates/registered/groupmanagement.html +++ b/stock/templates/registered/groupmanagement.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/groupmembers.html b/stock/templates/registered/groupmembers.html index 45c183ed..c25e58b5 100644 --- a/stock/templates/registered/groupmembers.html +++ b/stock/templates/registered/groupmembers.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/groupmembership.html b/stock/templates/registered/groupmembership.html index 9c57204b..84b520a5 100644 --- a/stock/templates/registered/groupmembership.html +++ b/stock/templates/registered/groupmembership.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/groups.html b/stock/templates/registered/groups.html index a96af407..9cd222c1 100644 --- a/stock/templates/registered/groups.html +++ b/stock/templates/registered/groups.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/help.html b/stock/templates/registered/help.html index 5856fa58..0cb73baa 100644 --- a/stock/templates/registered/help.html +++ b/stock/templates/registered/help.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% block title %}Alliance Auth{% endblock %} diff --git a/stock/templates/registered/hrapplicationcorpchoice.html b/stock/templates/registered/hrapplicationcorpchoice.html index 6dc7237b..fe924103 100644 --- a/stock/templates/registered/hrapplicationcorpchoice.html +++ b/stock/templates/registered/hrapplicationcorpchoice.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/hrapplicationcreate.html b/stock/templates/registered/hrapplicationcreate.html index 97737195..090887a8 100644 --- a/stock/templates/registered/hrapplicationcreate.html +++ b/stock/templates/registered/hrapplicationcreate.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/hrapplicationmanagement.html b/stock/templates/registered/hrapplicationmanagement.html index ebd5432b..3af1dce9 100755 --- a/stock/templates/registered/hrapplicationmanagement.html +++ b/stock/templates/registered/hrapplicationmanagement.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/hrapplicationsearchview.html b/stock/templates/registered/hrapplicationsearchview.html index 3826d04f..d82ebe04 100755 --- a/stock/templates/registered/hrapplicationsearchview.html +++ b/stock/templates/registered/hrapplicationsearchview.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/hrapplicationview.html b/stock/templates/registered/hrapplicationview.html index 40def5a8..ba643ab8 100644 --- a/stock/templates/registered/hrapplicationview.html +++ b/stock/templates/registered/hrapplicationview.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load staticfiles %} {% load bootstrap %} {% load i18n %} @@ -72,18 +72,6 @@ {% if buttons %} {% if perms.auth.human_resources %} - {% if perms.hrapplications.view_apis %} -
    -
    -
    {% trans 'API Keys' %}
    -
    - {% for api in apis %} - {{ api|api_link:'btn btn-info' }} - {% endfor %} -
    -
    -
    - {% endif %}
    {% trans "Actions" %}
    diff --git a/stock/templates/registered/jabberbroadcast.html b/stock/templates/registered/jabberbroadcast.html index b76f04d2..60535dcd 100755 --- a/stock/templates/registered/jabberbroadcast.html +++ b/stock/templates/registered/jabberbroadcast.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/notification_list.html b/stock/templates/registered/notification_list.html index 90bd8506..a32367aa 100644 --- a/stock/templates/registered/notification_list.html +++ b/stock/templates/registered/notification_list.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/notification_view.html b/stock/templates/registered/notification_view.html index 872e5ec8..b23702a9 100644 --- a/stock/templates/registered/notification_view.html +++ b/stock/templates/registered/notification_view.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/operationmanagement.html b/stock/templates/registered/operationmanagement.html index db4fa937..b117bf96 100644 --- a/stock/templates/registered/operationmanagement.html +++ b/stock/templates/registered/operationmanagement.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load staticfiles %} {% load i18n %} {% get_current_language as LANGUAGE_CODE %} diff --git a/stock/templates/registered/optimerupdate.html b/stock/templates/registered/optimerupdate.html index 318ec842..8fe98316 100755 --- a/stock/templates/registered/optimerupdate.html +++ b/stock/templates/registered/optimerupdate.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/service_credentials.html b/stock/templates/registered/service_credentials.html index b92082d1..6ac43ff6 100644 --- a/stock/templates/registered/service_credentials.html +++ b/stock/templates/registered/service_credentials.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/service_password.html b/stock/templates/registered/service_password.html index 51632898..b4b465a3 100644 --- a/stock/templates/registered/service_password.html +++ b/stock/templates/registered/service_password.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/services.html b/stock/templates/registered/services.html index 11c358b3..744c3db0 100755 --- a/stock/templates/registered/services.html +++ b/stock/templates/registered/services.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/srpfleetadd.html b/stock/templates/registered/srpfleetadd.html index 71f4bc2b..0b222f43 100755 --- a/stock/templates/registered/srpfleetadd.html +++ b/stock/templates/registered/srpfleetadd.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/srpfleetdata.html b/stock/templates/registered/srpfleetdata.html index ce526b04..1a1b510d 100755 --- a/stock/templates/registered/srpfleetdata.html +++ b/stock/templates/registered/srpfleetdata.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/srpfleetrequest.html b/stock/templates/registered/srpfleetrequest.html index 8cc91f18..954954cc 100755 --- a/stock/templates/registered/srpfleetrequest.html +++ b/stock/templates/registered/srpfleetrequest.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/srpfleetrequestamount.html b/stock/templates/registered/srpfleetrequestamount.html index 648f835f..c90e506d 100755 --- a/stock/templates/registered/srpfleetrequestamount.html +++ b/stock/templates/registered/srpfleetrequestamount.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/srpfleetupdate.html b/stock/templates/registered/srpfleetupdate.html index ef603113..5e67a65d 100755 --- a/stock/templates/registered/srpfleetupdate.html +++ b/stock/templates/registered/srpfleetupdate.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/srpmanagement.html b/stock/templates/registered/srpmanagement.html index 5bd9b408..06ed8f51 100755 --- a/stock/templates/registered/srpmanagement.html +++ b/stock/templates/registered/srpmanagement.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/teamspeakjoin.html b/stock/templates/registered/teamspeakjoin.html index 54e05c9a..f740e2e6 100644 --- a/stock/templates/registered/teamspeakjoin.html +++ b/stock/templates/registered/teamspeakjoin.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/stock/templates/registered/timermanagement.html b/stock/templates/registered/timermanagement.html index 7b7caf78..79813be8 100755 --- a/stock/templates/registered/timermanagement.html +++ b/stock/templates/registered/timermanagement.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load staticfiles %} {% load i18n %} {% get_current_language as LANGUAGE_CODE %} diff --git a/stock/templates/registered/timerupdate.html b/stock/templates/registered/timerupdate.html index bf59dc0c..e19dc041 100644 --- a/stock/templates/registered/timerupdate.html +++ b/stock/templates/registered/timerupdate.html @@ -1,4 +1,4 @@ -{% extends "public/base.html" %} +{% extends "registered/base.html" %} {% load bootstrap %} {% load staticfiles %} {% load i18n %} diff --git a/timerboard/migrations/0002_auto_20170322_2335.py b/timerboard/migrations/0002_auto_20170322_2335.py new file mode 100644 index 00000000..f1558890 --- /dev/null +++ b/timerboard/migrations/0002_auto_20170322_2335.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-03-22 23:35 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('timerboard', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='timer', + name='details', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='timer', + name='objective', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='timer', + name='planet_moon', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='timer', + name='structure', + field=models.CharField(default='', max_length=254), + ), + migrations.AlterField( + model_name='timer', + name='system', + field=models.CharField(default='', max_length=254), + ), + ] diff --git a/timerboard/views.py b/timerboard/views.py index 6bcd6b4c..84f5a871 100755 --- a/timerboard/views.py +++ b/timerboard/views.py @@ -5,12 +5,9 @@ from django.shortcuts import render, redirect from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import permission_required from django.shortcuts import get_object_or_404 -from authentication.decorators import members_and_blues from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from django.contrib import messages -from authentication.states import MEMBER_STATE, BLUE_STATE -from authentication.models import AuthServicesInfo from eveonline.managers import EveManager from timerboard.form import TimerForm from timerboard.models import Timer @@ -20,17 +17,11 @@ import logging logger = logging.getLogger(__name__) -def timer_util_test(user): - return AuthServicesInfo.objects.get(user=user).state in [BLUE_STATE, MEMBER_STATE] - - @login_required -@members_and_blues() @permission_required('auth.timer_view') def timer_view(request): logger.debug("timer_view called by user %s" % request.user) - auth_info = AuthServicesInfo.objects.get(user=request.user) - char = EveManager.get_character_by_id(auth_info.main_char_id) + char = request.user.profile.main_character if char: corp = EveManager.get_corporation_info_by_id(char.corporation_id) else: @@ -65,8 +56,7 @@ def add_timer_view(request): logger.debug("Request type POST contains form valid: %s" % form.is_valid()) if form.is_valid(): # Get character - auth_info = AuthServicesInfo.objects.get(user=request.user) - character = EveManager.get_character_by_id(auth_info.main_char_id) + character = request.user.profile.main_character corporation = EveManager.get_corporation_info_by_id(character.corporation_id) logger.debug( "Determined timer add request on behalf of character %s corporation %s" % (character, corporation)) @@ -107,15 +97,10 @@ def add_timer_view(request): @permission_required('auth.timer_management') def remove_timer(request, timer_id): logger.debug("remove_timer called by user %s for timer id %s" % (request.user, timer_id)) - if Timer.objects.filter(id=timer_id).exists(): - timer = Timer.objects.get(id=timer_id) - timer.delete() - logger.debug("Deleting timer id %s by user %s" % (timer_id, request.user)) - messages.success(request, _('Deleted timer in %(system)s at %(time)s.') % (timer.system, timer.eve_time)) - else: - logger.error( - "Unable to delete timer id %s for user %s - timer matching id not found." % (timer_id, request.user)) - messages.error(request, _('Unable to locate timer with ID %(timerid)s.') % {"timerid": timer_id}) + timer = get_object_or_404(Timer, id=timer_id) + timer.delete() + logger.debug("Deleting timer id %s by user %s" % (timer_id, request.user)) + messages.success(request, _('Deleted timer in %(system)s at %(time)s.') % (timer.system, timer.eve_time)) return redirect("auth_timer_view") @@ -128,8 +113,7 @@ def edit_timer(request, timer_id): form = TimerForm(request.POST) logger.debug("Received POST request containing updated timer form, is valid: %s" % form.is_valid()) if form.is_valid(): - auth_info = AuthServicesInfo.objects.get(user=request.user) - character = EveManager.get_character_by_id(auth_info.main_char_id) + character = request.user.profile.main_character corporation = EveManager.get_corporation_info_by_id(character.corporation_id) logger.debug( "Determined timer edit request on behalf of character %s corporation %s" % (character, corporation)) @@ -169,7 +153,6 @@ def edit_timer(request, timer_id): 'days_left': tddays, 'hours_left': tdhours, 'minutes_left': tdminutes, - } form = TimerForm(initial=data) return render(request, 'registered/timerupdate.html', context={'form': form}) diff --git a/update.sh b/update.sh index 9b25398f..936222e0 100755 --- a/update.sh +++ b/update.sh @@ -1,4 +1,4 @@ pip install --upgrade -r requirements.txt python manage.py migrate --fake-initial -yes yes | python manage.py collectstatic -python manage.py shell < run_alliance_corp_update.py +yes yes | python manage.py collectstatic -c +python manage.py check --deploy \ No newline at end of file