mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-09 20:40:17 +02:00
Bulk of the profile work is done.
This commit is contained in:
parent
bb87fdd958
commit
e15d79b834
@ -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:
|
||||
|
@ -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):
|
||||
|
@ -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<doctrinenumber>[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<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$'),
|
||||
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')),
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
13
authentication/checks.py
Normal file
13
authentication/checks.py
Normal file
@ -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
|
@ -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],
|
||||
}
|
@ -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)
|
@ -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)
|
||||
|
@ -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()
|
@ -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)
|
||||
]
|
||||
|
24
authentication/migrations/0014_fleetup_permission.py
Normal file
24
authentication/migrations/0014_fleetup_permission.py
Normal file
@ -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)
|
||||
]
|
227
authentication/migrations/0015_user_profiles.py
Normal file
227
authentication/migrations/0015_user_profiles.py
Normal file
@ -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',
|
||||
),
|
||||
]
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -1,4 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
MEMBER_STATE = 'Member'
|
||||
BLUE_STATE = 'Blue'
|
||||
NONE_STATE = None
|
@ -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)
|
94
authentication/templates/authentication/dashboard.html
Normal file
94
authentication/templates/authentication/dashboard.html
Normal file
@ -0,0 +1,94 @@
|
||||
{% extends "registered/base.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Dashboard" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">{% trans "Dashboard" %}</h1>
|
||||
<div class="col-lg-12 container">
|
||||
<div class="row">
|
||||
<div class="col-lg-6 text-center">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">{% trans "Main Character" %}</div>
|
||||
<div class="panel-body">
|
||||
{% if request.user.profile.main_character %}
|
||||
{% with request.user.profile.main_character as main %}
|
||||
<div class="col-lg-4 col-sm-2">
|
||||
<table class="table">
|
||||
<tr><td class="text-center"><img class="ra-avatar" src="https://image.eveonline.com/Character/{{ main.character_id }}_128.jpg"></td></tr>
|
||||
<tr><td class="text-center">{{ main.character_name }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-lg-4 col-sm-2">
|
||||
<table class="table">
|
||||
<tr><td class="text-center"><img class="ra-avatar" src="https://image.eveonline.com/Corporation/{{ main.corporation_id }}_128.png"></td></tr>
|
||||
<tr><td class="text-center">{{ main.corporation_name }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-lg-4 col-sm-2">
|
||||
{% if main.alliance_id %}
|
||||
<table class="table">
|
||||
<tr><td class="text-center"><img class="ra-avatar" src="https://image.eveonline.com/Alliance/{{ main.alliance_id }}_128.png"></td></tr>
|
||||
<tr><td class="text-center">{{ main.alliance_name }}</td><tr>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
<div class="alert alert-danger" role="alert">{% trans "Missing main character model." %}</div>
|
||||
{% endif %}
|
||||
<div class="clearfix"></div>
|
||||
<div class="col-xs-6">
|
||||
<a href="{% url 'authentication:add_character' %}" class="btn btn-block btn-info" title="Add Character">{% trans 'Add Character' %}</a>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<a href="{% url 'authentication:change_main_character' %}" class="btn btn-block btn-info" title="Change Main Character">{% trans "Change Main" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 text-center">
|
||||
<div class="panel panel-success">
|
||||
<div class="panel-heading">{% trans "Groups" %}</div>
|
||||
<div class="panel-body">
|
||||
<div style="height: 236px;overflow:-moz-scrollbars-vertical;overflow-y:auto;">
|
||||
<table class="table table-striped">
|
||||
{% for group in user.groups.all %}
|
||||
<tr>
|
||||
<td>{{ group.name }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" style="display:flex;">{% trans 'Characters' %}</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-hover">
|
||||
<tr>
|
||||
<th class="text-center"></th>
|
||||
<th class="text-center">{% trans 'Name' %}</th>
|
||||
<th class="text-center">{% trans 'Corp' %}</th>
|
||||
<th class="text-center">{% trans 'Alliance' %}</th>
|
||||
</tr>
|
||||
{% for ownership in request.user.character_ownerships.all %}
|
||||
{% with ownership.character as char %}
|
||||
<tr>
|
||||
<td class="text-center">{{ char.character_name }}</td>
|
||||
<td class="text-center">{{ char.corporation_name }}</td>
|
||||
<td class="text-center">{{ char.alliance_name }}</td>
|
||||
</tr>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
49
authentication/templates/public/base.html
Normal file
49
authentication/templates/public/base.html
Normal file
@ -0,0 +1,49 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
<title>{% block title %}{{ SITE_NAME }}{% endblock %}</title>
|
||||
|
||||
{% include 'bundles/bootstrap-css.html' %}
|
||||
{% include 'bundles/fontawesome.html' %}
|
||||
{% block extra_include %}
|
||||
{% endblock %}
|
||||
|
||||
<style>
|
||||
body {
|
||||
background: url('{% static 'img/index_images/index_blank_bg.jpg' %}') no-repeat scroll;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.panel-transparent {
|
||||
background: rgba(48, 48, 48, 0.7);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
|
||||
}
|
||||
|
||||
#lang_select {
|
||||
width: 40%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
{% block extra_style %}
|
||||
{% endblock %}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container" style="margin-top:150px">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
15
authentication/templates/public/lang_select.html
Normal file
15
authentication/templates/public/lang_select.html
Normal file
@ -0,0 +1,15 @@
|
||||
{% load i18n %}
|
||||
<div class="dropdown">
|
||||
<form action="{% url 'set_language' %}" method="post">
|
||||
{% csrf_token %}
|
||||
<input name="next" type="hidden" value="{{ request.get_full_path|slice:'3:' }}" />
|
||||
<select onchange="this.form.submit()" class="form-control" id="lang_select" name="language">
|
||||
{% get_language_info_list for LANGUAGES as languages %}
|
||||
{% for language in languages %}
|
||||
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected="selected"{% endif %}>
|
||||
{{ language.name_local }} ({{ language.code }})
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
27
authentication/templates/public/login.html
Normal file
27
authentication/templates/public/login.html
Normal file
@ -0,0 +1,27 @@
|
||||
{% extends 'public/base.html' %}
|
||||
{% block title %}Login{% endblock %}
|
||||
{% block content %}
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ message.level_tag}}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<div class="panel panel-default panel-transparent">
|
||||
<div class="panel-body">
|
||||
<div class="col-md-12">
|
||||
<p style="text-align:center">
|
||||
<a href="{% url 'auth_sso_login' %}">
|
||||
<img src="{% static 'img/sso/EVE_SSO_Login_Buttons_Large_Black.png' %}" border=0>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'public/lang_select.html' %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block extra_include %}
|
||||
{% include 'bundles/bootstrap-js.html' %}
|
||||
{% endblock %}
|
||||
|
24
authentication/templates/public/register.html
Normal file
24
authentication/templates/public/register.html
Normal file
@ -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 %}
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<div class="panel panel-default panel-transparent">
|
||||
<div class="panel-body">
|
||||
<form method="POST">
|
||||
{% csrf_token %}
|
||||
{{ form|bootstrap }}
|
||||
<button class="btn btn-lg btn-primary btn-block" type="submit">{% trans "Register" %}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'public/lang_select.html' %}
|
||||
</div>
|
||||
{% endblock %}
|
16
stock/templates/public/base.html → authentication/templates/registered/base.html
Executable file → Normal file
16
stock/templates/public/base.html → authentication/templates/registered/base.html
Executable file → Normal file
@ -104,20 +104,19 @@
|
||||
<li class="text-center divider-horizontal">
|
||||
<h5>{% trans "Aux Navigation" %}</h5>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a class="{% navactive request 'auth_services' %}" href="{% url 'auth_services' %}">
|
||||
<i class="fa fa-cogs fa-fw grayiconecolor"></i>{% trans " Services" %}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{% if not STATE == MEMBER_STATE or perms.auth.human_resources %}
|
||||
<li>
|
||||
<a class="{% navactive request 'auth_hrapplications_view auth_hrapplication_create_view auth_hrapplication_personal_view auth_hrapplication_search auth_hrapplication_view' %}"
|
||||
href="{% url 'auth_hrapplications_view' %}">
|
||||
<i class="fa fa-file-o fa-fw grayiconecolor"></i>{% trans " Applications" %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% if perms.corputils.view_corp_corpstats or perms.corputils.view_alliance_corpstats or perms.corputils.view_blue_corpstats %}
|
||||
<li>
|
||||
@ -135,16 +134,14 @@
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% if STATE in MEMBER_BLUE_STATE or user.is_superuser %}
|
||||
{% if perms.auth.view_fleetup %}
|
||||
<li>
|
||||
<a class="{% navactive request 'auth_fleetup_view auth_fleetup_fittings auth_fleetup_fitting auth_fleetup_doctrines auth_fleetup_doctrine auth_fleetup_characters' %}" href="{% url 'auth_fleetup_view' %}">
|
||||
<i class="fa fa-clock-o fa-fw grayiconecolor"></i> Fleet-Up
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if STATE in MEMBER_BLUE_STATE or user.is_superuser %}
|
||||
{% if perms.auth.optimer_view %}
|
||||
<li>
|
||||
<a class="{% navactive request 'auth_optimer_view auth_add_optimer_view auth_edit_optimer' %}" href="{% url 'auth_optimer_view' %}">
|
||||
@ -152,6 +149,7 @@
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% if perms.auth.timer_view %}
|
||||
<li>
|
||||
<a class="{% navactive request 'auth_timer_view auth_add_timer_view auth_edit_timer' %}" href="{% url 'auth_timer_view' %}">
|
||||
@ -171,18 +169,12 @@
|
||||
<i class="fa fa-money fa-fw grayiconecolor"></i>{% trans " Ship Replacement" %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% menu_aux %}
|
||||
<li class="text-center divider-horizontal">
|
||||
<h5>{% trans "Util" %}</h5>
|
||||
</li>
|
||||
<li>
|
||||
<a class="{% navactive request 'password_change password_change_done' %}" href="{% url 'password_change' %}">
|
||||
<i class="fa fa-lock fa-fw grayiconecolor"></i>{% trans "Change Password" %}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{% 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 %}
|
||||
<li>
|
||||
<a class="{% navactive request 'auth_fleet_format_tool_view' %}" href="{% url 'auth_fleet_format_tool_view' %}">
|
||||
<i class="fa fa-space-shuttle fa-fw grayiconecolor"></i>{% trans " Fleet Broadcast Formatter" %}
|
@ -1,4 +1,4 @@
|
||||
{% extends "public/base.html" %}
|
||||
{% extends "registered/base.html" %}
|
||||
{% load bootstrap %}
|
||||
{% load i18n static %}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{% extends "public/base.html" %}
|
||||
{% extends "registered/base.html" %}
|
||||
{% load bootstrap %}
|
||||
{% load i18n static %}
|
||||
|
@ -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)
|
21
authentication/urls.py
Normal file
21
authentication/urls.py
Normal file
@ -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'),
|
||||
]
|
@ -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.'))
|
||||
@login_required
|
||||
@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:
|
||||
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:
|
||||
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})
|
||||
messages.error(request, _('Failed to add %(name)s to your account.' % ({'name': token.charater_name})))
|
||||
return redirect('authentication:dashboard')
|
||||
|
||||
|
||||
def index_view(request):
|
||||
logger.debug("index_view called by user %s" % request.user)
|
||||
return render(request, 'public/index.html')
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
|
||||
|
||||
@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)
|
||||
# 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:
|
||||
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)
|
||||
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
|
||||
|
@ -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()
|
||||
|
||||
|
||||
|
19
corputils/migrations/0003_auto_20170322_2335.py
Normal file
19
corputils/migrations/0003_auto_20170322_2335.py
Normal file
@ -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'},
|
||||
),
|
||||
]
|
@ -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):
|
||||
|
@ -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 %}
|
||||
|
@ -58,9 +58,6 @@
|
||||
<tr>
|
||||
<th></th>
|
||||
<th class="text-center">{% trans "Character" %}</th>
|
||||
{% if corpstats.show_apis %}
|
||||
<th class="text-center">API</th>
|
||||
{% endif %}
|
||||
<th class="text-center">{% trans "zKillboard" %}</th>
|
||||
<th class="text-center">{% trans "Main Character" %}</th>
|
||||
<th class="text-center">{% trans "Main Corporation" %}</th>
|
||||
@ -70,13 +67,6 @@
|
||||
<tr {% if not member.registered %}class="danger"{% endif %}>
|
||||
<td><img src="{{ member.portrait_url }}" class="img-circle"></td>
|
||||
<td class="text-center">{{ member.character_name }}</td>
|
||||
{% if corpstats.show_apis %}
|
||||
{% if member.api %}
|
||||
<td class="text-center">{{ member.api|api_link:'label label-primary' }}</td>
|
||||
{% else %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<td class="text-center"><a href="https://zkillboard.com/character/{{ member.character_id }}/" class="label label-danger" target="_blank">{% trans "Killboard" %}</a></td>
|
||||
<td class="text-center">{{ member.main.character_name }}</td>
|
||||
<td class="text-center">{{ member.main.corporation_name }}</td>
|
||||
|
@ -16,7 +16,6 @@
|
||||
<th class="text-center"></th>
|
||||
<th class="text-center">{% trans "Character" %}</th>
|
||||
<th class="text-center">{% trans "Corporation" %}</th>
|
||||
<th class="text-center">{% trans "API" %}</th>
|
||||
<th class="text-center">{% trans "zKillboard" %}</th>
|
||||
<th class="text-center">{% trans "Main Character" %}</th>
|
||||
<th class="text-center">{% trans "Main Corporation" %}</th>
|
||||
@ -27,11 +26,6 @@
|
||||
<td class="text-center"><img src="{{ result.1.portrait_url }}" class="img-circle"></td>
|
||||
<td class="text-center">{{ result.1.character_name }}</td>
|
||||
<td class="text-center">{{ result.0.corp.corporation_name }}</td>
|
||||
{% if result.1.api %}
|
||||
<td class="text-center">{{ result.1.api|api_link:"label label-primary" }}</td>
|
||||
{% else %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
<td class="text-center"><a href="https://zkillboard.com/character/{{ result.1.character_id }}/" class="label label-danger" target="_blank">{% trans "Killboard" %}</a></td>
|
||||
<td class="text-center">{{ result.1.main.character_name }}</td>
|
||||
<td class="text-center">{{ result.1.main.corporation_name }}</td>
|
||||
|
@ -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)
|
||||
|
@ -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 main_character(obj):
|
||||
if obj.user:
|
||||
auth = AuthServicesInfo.objects.get(user=obj.user)
|
||||
if auth and auth.main_char_id:
|
||||
def user(obj):
|
||||
try:
|
||||
return EveCharacter.objects.get(character_id=auth.main_char_id)
|
||||
except EveCharacter.DoesNotExist:
|
||||
pass
|
||||
return obj.character_ownership.user
|
||||
except (AttributeError, ObjectDoesNotExist):
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def main_character(obj):
|
||||
try:
|
||||
return obj.character_ownership.user.profile.main_character
|
||||
except (AttributeError, ObjectDoesNotExist):
|
||||
return None
|
||||
|
||||
|
||||
admin.site.register(EveCharacter, EveCharacterAdmin)
|
||||
admin.site.register(EveApiKeyPair, EveApiKeyPairAdmin)
|
||||
|
@ -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)
|
@ -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)
|
||||
|
38
eveonline/migrations/0008_remove_apikeys.py
Normal file
38
eveonline/migrations/0008_remove_apikeys.py
Normal file
@ -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',
|
||||
),
|
||||
]
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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 = "<a href='{url}' class='{style}' target='_new'>{api_id}</a>".format(url=url, style=style_class,
|
||||
api_id=api.api_id)
|
||||
else:
|
||||
element = "<a href='#' class='{style}' onclick='return prompt({prompt}, {vcode})'>{api_id}</a>".format(
|
||||
style=style_class, prompt='"Verification Code"', vcode='"%s"' % api.api_key, api_id=api.api_id)
|
||||
return mark_safe(element)
|
@ -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")
|
||||
|
@ -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'))
|
||||
|
20
fleetactivitytracking/migrations/0004_auto_20170322_2335.py
Normal file
20
fleetactivitytracking/migrations/0004_auto_20170322_2335.py
Normal file
@ -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),
|
||||
),
|
||||
]
|
@ -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 %}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{% extends "public/base.html" %}
|
||||
{% extends "registered/base.html" %}
|
||||
{% load bootstrap %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{% extends "public/base.html" %}
|
||||
{% extends "registered/base.html" %}
|
||||
{% load bootstrap %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{% extends "public/base.html" %}
|
||||
{% extends "registered/base.html" %}
|
||||
{% load bootstrap %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{% extends "public/base.html" %}
|
||||
{% extends "registered/base.html" %}
|
||||
{% load bootstrap %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{% extends "public/base.html" %}
|
||||
{% extends "registered/base.html" %}
|
||||
{% load bootstrap %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{% extends "public/base.html" %}
|
||||
{% extends "registered/base.html" %}
|
||||
{% load bootstrap %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
|
@ -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,8 +197,7 @@ 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)):
|
||||
|
||||
@ -245,10 +244,6 @@ def click_fatlink_view(request, token, hash, fatname):
|
||||
return render(request, 'fleetactivitytracking/characternotexisting.html', context=context)
|
||||
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')
|
||||
|
||||
|
||||
@login_required
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)))
|
||||
|
50
hrapplications/migrations/0002_auto_20170322_2335.py
Normal file
50
hrapplications/migrations/0002_auto_20170322_2335.py
Normal file
@ -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),
|
||||
),
|
||||
]
|
@ -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:
|
||||
|
@ -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))
|
||||
|
@ -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 "
|
||||
|
||||
|
@ -19,7 +19,8 @@ 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(
|
||||
|
20
notifications/migrations/0003_auto_20170322_2335.py
Normal file
20
notifications/migrations/0003_auto_20170322_2335.py
Normal file
@ -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),
|
||||
),
|
||||
]
|
@ -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)
|
||||
|
@ -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"))
|
||||
|
50
optimer/migrations/0002_auto_20170322_2335.py
Normal file
50
optimer/migrations/0002_auto_20170322_2335.py
Normal file
@ -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),
|
||||
),
|
||||
]
|
@ -7,7 +7,7 @@ from datetime import datetime
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class optimer(models.Model):
|
||||
class OpTimer(models.Model):
|
||||
class Meta:
|
||||
ordering = ['start']
|
||||
|
||||
|
@ -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 = 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})
|
||||
else:
|
||||
logger.error("Unable to delete optimer id %s for user %s - operation matching id not found." % (
|
||||
optimer_id, request.user))
|
||||
return redirect("auth_optimer_view")
|
||||
|
||||
|
||||
@ -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})
|
||||
|
@ -1,4 +1,4 @@
|
||||
{% extends "public/base.html" %}
|
||||
{% extends "registered/base.html" %}
|
||||
{% load bootstrap %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{% extends "public/base.html" %}
|
||||
{% extends "registered/base.html" %}
|
||||
{% load bootstrap %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
|
@ -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
|
||||
|
@ -1,5 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
from eveonline.tasks import run_corp_update
|
||||
|
||||
run_corp_update()
|
||||
quit()
|
@ -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
|
||||
|
12
services/management/commands/verify_service_accounts.py
Normal file
12
services/management/commands/verify_service_accounts.py
Normal file
@ -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.'))
|
@ -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
|
20
services/migrations/0003_auto_20170322_2335.py
Normal file
20
services/migrations/0003_auto_20170322_2335.py
Normal file
@ -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),
|
||||
),
|
||||
]
|
@ -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
|
||||
|
@ -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,7 +98,8 @@ 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)
|
||||
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)
|
||||
@ -110,6 +111,8 @@ class DiscordTasks:
|
||||
# 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)
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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] != "":
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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,19 +20,10 @@ 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))
|
||||
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:
|
||||
|
@ -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[
|
||||
|
@ -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
|
||||
|
@ -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 != "":
|
||||
|
@ -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 == {}:
|
||||
|
@ -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))
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user