Bulk of the profile work is done.

This commit is contained in:
Adarnof 2017-03-23 22:54:25 -04:00
parent bb87fdd958
commit e15d79b834
155 changed files with 1693 additions and 3080 deletions

View File

@ -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:

View File

@ -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):

View File

@ -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')),

View File

@ -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

View File

@ -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)

View File

@ -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
View 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

View File

@ -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],
}

View File

@ -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)

View File

@ -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)

View File

@ -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()

View File

@ -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)
]

View 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)
]

View 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',
),
]

View File

@ -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)

View File

@ -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()

View File

@ -1,4 +0,0 @@
from __future__ import unicode_literals
MEMBER_STATE = 'Member'
BLUE_STATE = 'Blue'
NONE_STATE = None

View File

@ -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)

View 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 %}

View 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>

View 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>

View 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 %}

View 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 %}

View 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 %}
<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>
{% if perms.corputils.view_corp_corpstats or perms.corputils.view_alliance_corpstats or perms.corputils.view_blue_corpstats %}
<li>
@ -135,54 +134,47 @@
</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 %}
{% endif %}
{% if STATE in MEMBER_BLUE_STATE or user.is_superuser %}
{% if perms.auth.optimer_view %}
{% 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' %}">
<i class="fa fa-exclamation fa-fw grayiconecolor"></i>{% trans " Fleet Operations" %}
</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' %}">
<i class="fa fa-clock-o fa-fw grayiconecolor"></i>{% trans " Structure Timers" %}
</a>
</li>
{% endif %}
{% endif %}
{% if perms.auth.timer_view %}
<li>
<a class="{% navactive request 'auth_fatlink_view auth_fatlink_view_statistics auth_fatlink_view_statistics_month auth_fatlink_view_personal_statistics auth_fatlink_view_personal_statistics_year auth_fatlink_view_personal_statistics_month auth_fatlink_view_user_statistics_month auth_create_fatlink_view auth_modify_fatlink_view auth_click_fatlink_view' %}" href="{% url 'auth_fatlink_view' %}">
<i class="fa fa-users fa-lightbulb-o fa-fw grayiconecolor"></i>{% trans " Fleet Activity Tracking" %}
</a>
</li>
<li>
<a class="{% navactive request 'auth_srp_management_view auth_srp_management_all_view auth_srp_fleet_view auth_srp_fleet_add_view auth_srp_fleet_edit_view auth_srp_request_view auth_srp_request_update_amount_view' %}" href="{% url 'auth_srp_management_view' %}">
<i class="fa fa-money fa-fw grayiconecolor"></i>{% trans " Ship Replacement" %}
<a class="{% navactive request 'auth_timer_view auth_add_timer_view auth_edit_timer' %}" href="{% url 'auth_timer_view' %}">
<i class="fa fa-clock-o fa-fw grayiconecolor"></i>{% trans " Structure Timers" %}
</a>
</li>
{% endif %}
<li>
<a class="{% navactive request 'auth_fatlink_view auth_fatlink_view_statistics auth_fatlink_view_statistics_month auth_fatlink_view_personal_statistics auth_fatlink_view_personal_statistics_year auth_fatlink_view_personal_statistics_month auth_fatlink_view_user_statistics_month auth_create_fatlink_view auth_modify_fatlink_view auth_click_fatlink_view' %}" href="{% url 'auth_fatlink_view' %}">
<i class="fa fa-users fa-lightbulb-o fa-fw grayiconecolor"></i>{% trans " Fleet Activity Tracking" %}
</a>
</li>
<li>
<a class="{% navactive request 'auth_srp_management_view auth_srp_management_all_view auth_srp_fleet_view auth_srp_fleet_add_view auth_srp_fleet_edit_view auth_srp_request_view auth_srp_request_update_amount_view' %}" href="{% url 'auth_srp_management_view' %}">
<i class="fa fa-money fa-fw grayiconecolor"></i>{% trans " Ship Replacement" %}
</a>
</li>
{% 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" %}

View File

@ -1,4 +1,4 @@
{% extends "public/base.html" %}
{% extends "registered/base.html" %}
{% load bootstrap %}
{% load i18n static %}

View File

@ -1,4 +1,4 @@
{% extends "public/base.html" %}
{% extends "registered/base.html" %}
{% load bootstrap %}
{% load i18n static %}

View File

@ -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
View 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'),
]

View File

@ -1,116 +1,123 @@
from __future__ import unicode_literals
from django.contrib.auth import login
from django.contrib.auth import logout
from django.contrib.auth import authenticate
from django.shortcuts import render, redirect
from django.contrib.auth import login, authenticate
from django.shortcuts import redirect
from django.contrib.auth.decorators import login_required
from django.utils.translation import ugettext_lazy as _
from eveonline.managers import EveManager
from eveonline.models import EveCharacter
from authentication.models import AuthServicesInfo
from authentication.forms import LoginForm, RegistrationForm
from django.contrib.auth.models import User
from authentication.forms import RegistrationForm
from authentication.models import CharacterOwnership
from django.contrib import messages
from django.contrib.auth.models import User
from django.conf import settings
from django.core import signing
from esi.decorators import token_required
from registration.backends.hmac.views import RegistrationView as BaseRegistrationView, \
ActivationView as BaseActivationView, REGISTRATION_SALT
from registration.signals import user_registered
import logging
logger = logging.getLogger(__name__)
def login_user(request):
logger.debug("login_user called by user %s" % request.user)
if request.method == 'POST':
form = LoginForm(request.POST)
logger.debug("Request of type POST, received form, valid: %s" % form.is_valid())
if form.is_valid():
user = authenticate(username=form.cleaned_data['username'], password=form.cleaned_data['password'])
logger.debug("Authentication attempt with supplied credentials. Received user %s" % user)
if user is not None:
if user.is_active:
logger.info("Successful login attempt from user %s" % user)
login(request, user)
redirect_to = request.POST.get('next', request.GET.get('next', ''))
if not redirect_to:
redirect_to = 'auth_dashboard'
return redirect(redirect_to)
else:
logger.info("Login attempt failed for user %s: user marked inactive." % user)
messages.warning(request, _('Your account has been disabled.'))
else:
logger.info("Failed login attempt: provided username %s" % form.cleaned_data['username'])
messages.error(request, _('Username/password invalid.'))
return render(request, 'public/login.html', context={'form': form})
else:
logger.debug("Providing new login form.")
form = LoginForm()
return render(request, 'public/login.html', context={'form': form})
def logout_user(request):
logger.debug("logout_user called by user %s" % request.user)
temp_user = request.user
logout(request)
logger.info("Successful logout for user %s" % temp_user)
return redirect("auth_index")
def register_user_view(request):
logger.debug("register_user_view called by user %s" % request.user)
if request.method == 'POST':
form = RegistrationForm(request.POST)
logger.debug("Request type POST contains form valid: %s" % form.is_valid())
if form.is_valid():
if not User.objects.filter(username=form.cleaned_data['username']).exists():
user = User.objects.create_user(form.cleaned_data['username'],
form.cleaned_data['email'], form.cleaned_data['password'])
user.save()
logger.info("Created new user %s" % user)
login(request, user)
messages.warning(request, _('Add an API key to set up your account.'))
return redirect("auth_dashboard")
else:
logger.error("Unable to register new user: username %s already exists." % form.cleaned_data['username'])
return render(request, 'public/register.html', context={'form': form, 'error': True})
else:
logger.debug("Registration form invalid. Returning for user %s to make corrections." % request.user)
else:
logger.debug("Returning blank registration form.")
form = RegistrationForm()
return render(request, 'public/register.html', context={'form': form})
def index_view(request):
logger.debug("index_view called by user %s" % request.user)
return render(request, 'public/index.html')
@login_required
def help_view(request):
logger.debug("help_view called by user %s" % request.user)
return render(request, 'registered/help.html')
@token_required(new=True)
def sso_login(request, token):
@token_required(scopes=settings.LOGIN_TOKEN_SCOPES)
def main_character_change(request, token):
logger.debug("main_character_change called by user %s for character %s" % (request.user, token.character_name))
try:
char = EveCharacter.objects.get(character_id=token.character_id)
if char.user:
if char.user.is_active:
login(request, char.user)
token.user = char.user
token.save()
return redirect('auth_dashboard')
else:
messages.error(request, _('Your account has been disabled.'))
else:
messages.warning(request,
_('Authenticated character has no owning account. Please log in with username and password.'))
except EveCharacter.DoesNotExist:
messages.error(request, _('No account exists with the authenticated character. Please create an account first.'))
return redirect(login_user)
co = CharacterOwnership.objects.get(character__character_id=token.character_id)
except CharacterOwnership.DoesNotExist:
co = CharacterOwnership.objects.create_by_token(token)
request.user.profile.main_character = co.character
request.user.profile.save(update_fields=['main_character'])
messages.success(request, _('Changed main character to %(char)s') % {"char": co.character})
return redirect("auth_dashboard")
@token_required(new=True, scopes=settings.LOGIN_TOKEN_SCOPES)
def add_character(request, token):
if CharacterOwnership.objects.filter(character__character_id=token.character_id).filter(
owner_hash=token.character_owner_hash).filter(user=request.user).exists():
messages.success(request, _('Added %(name)s to your account.'% ({'name': token.character_name})))
else:
messages.error(request, _('Failed to add %(name)s to your account.' % ({'name': token.charater_name})))
return redirect('authentication:dashboard')
"""
Override the HMAC two-step registration view to accommodate the three-step registration required.
Step 1: OAuth token to create user and profile.
Step 2: Get email and send activation link (but do not save email).
Step 3: Get link, save email and activate.
Step 1 is necessary to automatically assign character ownership and a main character, both of which require a saved User
model - this means the ensuing registration form cannot create the user because it already exists.
Email is not saved to the user model in Step 2 as a way of differentiating users who have not yet completed registration
(is_active=False) and users who have been disabled by an admin (is_active=False, email present).
Because of this, the email address needs to be assigned in Step 3 after clicking the link, which means the link must
have the email address embedded much like the username. Key creation and decoding is overridden to support this action.
"""
# Step 1
@token_required(new=True, scopes=settings.LOGIN_TOKEN_SCOPES)
def sso_login(request, token):
user = authenticate(token=token)
if user and user.is_active:
login(request, user)
return redirect(request.POST.get('next', request.GET.get('next', 'auth_dashboard')))
elif user and not user.email:
# Store the new user PK in the session to enable us to identify the registering user in Step 2
request.session['registration_uid'] = user.pk
# Go to Step 2
return redirect('authentication:register')
else:
messages.error(request, _('Unable to authenticate as the selected character.'))
return redirect(settings.LOGIN_URL)
# Step 2
class RegistrationView(BaseRegistrationView):
form_class = RegistrationForm
success_url = 'authentication:dashboard'
def dispatch(self, *args, **kwargs):
# We're storing a key in the session to pass user information from OAuth response. Make sure it's there.
if not self.request.session.get('registration_uid', None) or not User.objects.filter(
pk=self.request.session.get('registration_uid')).exists():
messages.error(self.request, _('Registration token has expired.'))
return redirect(settings.LOGIN_URL)
return super(RegistrationView, self).dispatch(*args, **kwargs)
def register(self, form):
user = User.objects.get(pk=self.request.session.get('registration_uid'))
user.email = form.cleaned_data['email']
user_registered.send(self.__class__, user=user, request=self.request)
# Go to Step 3
self.send_activation_email(user)
return user
def get_activation_key(self, user):
return signing.dumps(obj=[getattr(user, User.USERNAME_FIELD), user.email], salt=REGISTRATION_SALT)
# Step 3
class ActivationView(BaseActivationView):
def validate_key(self, activation_key):
try:
dump = signing.loads(activation_key, salt=REGISTRATION_SALT,
max_age=settings.ACCOUNT_ACTIVATION_DAYS * 86400)
return dump
except signing.BadSignature:
return None
def activate(self, *args, **kwargs):
dump = self.validate_key(kwargs.get('activation_key'))
if dump:
user = self.get_user(dump[0])
if user:
user.email = dump[1]
user.is_active = True
user.save()
return user
return False

View File

@ -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()

View 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'},
),
]

View File

@ -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):

View File

@ -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 %}

View File

@ -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>

View File

@ -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>

View File

@ -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)

View File

@ -1,46 +1,31 @@
from __future__ import unicode_literals
from django.contrib import admin
from django.core.exceptions import ObjectDoesNotExist
from eveonline.models import EveCharacter
from eveonline.models import EveApiKeyPair
from eveonline.models import EveAllianceInfo
from eveonline.models import EveCorporationInfo
from authentication.models import AuthServicesInfo
admin.site.register(EveAllianceInfo)
admin.site.register(EveCorporationInfo)
class EveApiKeyPairAdmin(admin.ModelAdmin):
search_fields = ['api_id', 'user__username']
list_display = ['api_id', 'user', 'characters']
@staticmethod
def characters(obj):
return ', '.join(sorted([c.character_name for c in EveCharacter.objects.filter(api_id=obj.api_id)]))
def get_search_results(self, request, queryset, search_term):
queryset, use_distinct = super(EveApiKeyPairAdmin, self).get_search_results(request, queryset, search_term)
chars = EveCharacter.objects.filter(character_name__icontains=search_term)
queryset |= EveApiKeyPair.objects.filter(api_id__in=[char.api_id for char in chars if bool(char.api_id)])
return queryset, use_distinct
class EveCharacterAdmin(admin.ModelAdmin):
search_fields = ['character_name', 'corporation_name', 'alliance_name', 'user__username', 'api_id']
search_fields = ['character_name', 'corporation_name', 'alliance_name', 'character_ownership__user__username']
list_display = ('character_name', 'corporation_name', 'alliance_name', 'user', 'main_character')
@staticmethod
def user(obj):
try:
return obj.character_ownership.user
except (AttributeError, ObjectDoesNotExist):
return None
@staticmethod
def main_character(obj):
if obj.user:
auth = AuthServicesInfo.objects.get(user=obj.user)
if auth and auth.main_char_id:
try:
return EveCharacter.objects.get(character_id=auth.main_char_id)
except EveCharacter.DoesNotExist:
pass
return None
try:
return obj.character_ownership.user.profile.main_character
except (AttributeError, ObjectDoesNotExist):
return None
admin.site.register(EveCharacter, EveCharacterAdmin)
admin.site.register(EveApiKeyPair, EveApiKeyPairAdmin)

View File

@ -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)

View File

@ -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)

View 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',
),
]

View File

@ -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):

View File

@ -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

View File

@ -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()

View File

@ -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)

View File

@ -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")

View File

@ -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'))

View 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),
),
]

View File

@ -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 %}

View File

@ -1,4 +1,4 @@
{% extends "public/base.html" %}
{% extends "registered/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% load i18n %}

View File

@ -1,4 +1,4 @@
{% extends "public/base.html" %}
{% extends "registered/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% load i18n %}

View File

@ -1,4 +1,4 @@
{% extends "public/base.html" %}
{% extends "registered/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% load i18n %}

View File

@ -1,4 +1,4 @@
{% extends "public/base.html" %}
{% extends "registered/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% load i18n %}

View File

@ -1,4 +1,4 @@
{% extends "public/base.html" %}
{% extends "registered/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% load i18n %}

View File

@ -1,4 +1,4 @@
{% extends "public/base.html" %}
{% extends "registered/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% load i18n %}

View File

@ -1,6 +1,6 @@
from __future__ import unicode_literals
from django.conf import settings
from django.shortcuts import render, redirect
from django.shortcuts import render, redirect, get_object_or_404
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import permission_required
@ -197,58 +197,53 @@ def fatlink_monthly_personal_statistics_view(request, year, month, char_id=None)
@token_required(
scopes=['esi-location.read_location.v1', 'esi-location.read_ship_type.v1', 'esi-universe.read_structures.v1'])
def click_fatlink_view(request, token, hash, fatname):
try:
fatlink = Fatlink.objects.filter(hash=hash)[0]
fatlink = get_object_or_404(Fatlink, hash=hash, name=fatname)
if (timezone.now() - fatlink.fatdatetime) < datetime.timedelta(seconds=(fatlink.duration * 60)):
if (timezone.now() - fatlink.fatdatetime) < datetime.timedelta(seconds=(fatlink.duration * 60)):
character = EveManager.get_character_by_id(token.character_id)
character = EveManager.get_character_by_id(token.character_id)
if character:
# get data
c = token.get_esi_client(Location='v1', Universe='v2')
location = c.Location.get_characters_character_id_location(character_id=token.character_id).result()
ship = c.Location.get_characters_character_id_ship(character_id=token.character_id).result()
location['solar_system_name'] = \
c.Universe.get_universe_systems_system_id(system_id=location['solar_system_id']).result()[
if character:
# get data
c = token.get_esi_client(Location='v1', Universe='v2')
location = c.Location.get_characters_character_id_location(character_id=token.character_id).result()
ship = c.Location.get_characters_character_id_ship(character_id=token.character_id).result()
location['solar_system_name'] = \
c.Universe.get_universe_systems_system_id(system_id=location['solar_system_id']).result()[
'name']
if location['structure_id']:
location['station_name'] = \
c.Universe.get_universe_structures_structure_id(structure_id=location['structure_id']).result()[
'name']
if location['structure_id']:
location['station_name'] = \
c.Universe.get_universe_structures_structure_id(structure_id=location['structure_id']).result()[
'name']
elif location['station_id']:
location['station_name'] = \
c.Universe.get_universe_stations_station_id(station_id=location['station_id']).result()['name']
else:
location['station_name'] = "No Station"
ship['ship_type_name'] = EveManager.get_itemtype(ship['ship_type_id']).name
fat = Fat()
fat.system = location['solar_system_name']
fat.station = location['station_name']
fat.shiptype = ship['ship_type_name']
fat.fatlink = fatlink
fat.character = character
fat.user = character.user
try:
fat.full_clean()
fat.save()
messages.success(request, _('Fleet participation registered.'))
except ValidationError as e:
err_messages = []
for errorname, message in e.message_dict.items():
err_messages.append(message[0].decode())
messages.error(request, ' '.join(err_messages))
elif location['station_id']:
location['station_name'] = \
c.Universe.get_universe_stations_station_id(station_id=location['station_id']).result()['name']
else:
context = {'character_id': token.character_id,
'character_name': token.character_name}
return render(request, 'fleetactivitytracking/characternotexisting.html', context=context)
location['station_name'] = "No Station"
ship['ship_type_name'] = EveManager.get_itemtype(ship['ship_type_id']).name
fat = Fat()
fat.system = location['solar_system_name']
fat.station = location['station_name']
fat.shiptype = ship['ship_type_name']
fat.fatlink = fatlink
fat.character = character
fat.user = character.user
try:
fat.full_clean()
fat.save()
messages.success(request, _('Fleet participation registered.'))
except ValidationError as e:
err_messages = []
for errorname, message in e.message_dict.items():
err_messages.append(message[0].decode())
messages.error(request, ' '.join(err_messages))
else:
messages.error(request, _('FAT link has expired.'))
except (ObjectDoesNotExist, KeyError):
logger.exception("Failed to process FAT link.")
messages.error(request, _('Invalid FAT link.'))
return redirect('auth_fatlink_view')
context = {'character_id': token.character_id,
'character_name': token.character_name}
return render(request, 'fleetactivitytracking/characternotexisting.html', context=context)
else:
messages.error(request, _('FAT link has expired.'))
@login_required

View File

@ -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)

View File

@ -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

View File

@ -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)))

View 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),
),
]

View File

@ -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:

View File

@ -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))

View File

@ -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 " Schiffs 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 "

View File

@ -19,14 +19,15 @@ class NotificationHandler(logging.Handler):
message += "\n\n"
message = message + record.exc_text
users = User.objects.filter(Q(groups__permissions=perm) | Q(user_permissions=perm) | Q(is_superuser=True)).distinct()
users = User.objects.filter(
Q(groups__permissions=perm) | Q(user_permissions=perm) | Q(is_superuser=True)).distinct()
for user in users:
notify(
user,
"%s [%s:%s]" % (record.levelname, record.funcName, record.lineno),
level = str([item[0] for item in Notification.LEVEL_CHOICES if item[1] == record.levelname][0]),
message = message
level=str([item[0] for item in Notification.LEVEL_CHOICES if item[1] == record.levelname][0]),
message=message
)
except Permission.DoesNotExist:
pass

View 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),
),
]

View File

@ -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)

View File

@ -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"))

View 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),
),
]

View File

@ -7,7 +7,7 @@ from datetime import datetime
@python_2_unicode_compatible
class optimer(models.Model):
class OpTimer(models.Model):
class Meta:
ordering = ['start']

View File

@ -6,11 +6,8 @@ from django.utils.translation import ugettext_lazy as _
from django.shortcuts import get_object_or_404
from django.shortcuts import render, redirect
from django.contrib import messages
from authentication.models import AuthServicesInfo
from eveonline.managers import EveManager
from optimer.form import opForm
from optimer.models import optimer
from authentication.decorators import members_and_blues
from optimer.form import OpForm
from optimer.models import OpTimer
import logging
@ -18,11 +15,10 @@ logger = logging.getLogger(__name__)
@login_required
@members_and_blues()
@permission_required('auth.optimer_view')
def optimer_view(request):
logger.debug("optimer_view called by user %s" % request.user)
render_items = {'optimer': optimer.objects.all(), }
render_items = {'optimer': OpTimer.objects.all(), }
return render(request, 'registered/operationmanagement.html', context=render_items)
@ -32,16 +28,15 @@ def optimer_view(request):
def add_optimer_view(request):
logger.debug("add_optimer_view called by user %s" % request.user)
if request.method == 'POST':
form = opForm(request.POST)
form = OpForm(request.POST)
logger.debug("Request type POST contains form valid: %s" % form.is_valid())
if form.is_valid():
# Get Current Time
post_time = timezone.now()
# Get character
auth_info = AuthServicesInfo.objects.get(user=request.user)
character = EveManager.get_character_by_id(auth_info.main_char_id)
character = request.user.profile.main_character
# handle valid form
op = optimer()
op = OpTimer()
op.doctrine = form.cleaned_data['doctrine']
op.system = form.cleaned_data['system']
op.location = form.cleaned_data['location']
@ -58,7 +53,7 @@ def add_optimer_view(request):
return redirect("/optimer/")
else:
logger.debug("Returning new opForm")
form = opForm()
form = OpForm()
render_items = {'form': form}
@ -69,14 +64,10 @@ def add_optimer_view(request):
@permission_required('auth.optimer_management')
def remove_optimer(request, optimer_id):
logger.debug("remove_optimer called by user %s for operation id %s" % (request.user, optimer_id))
if optimer.objects.filter(id=optimer_id).exists():
op = optimer.objects.get(id=optimer_id)
op.delete()
logger.info("Deleting optimer id %s by user %s" % (optimer_id, request.user))
messages.success(request, _('Removed operation timer for %(opname)s.') % {"opname": op.operation_name})
else:
logger.error("Unable to delete optimer id %s for user %s - operation matching id not found." % (
optimer_id, request.user))
op = get_object_or_404(OpTimer, id=optimer_id)
op.delete()
logger.info("Deleting optimer id %s by user %s" % (optimer_id, request.user))
messages.success(request, _('Removed operation timer for %(opname)s.') % {"opname": op.operation_name})
return redirect("auth_optimer_view")
@ -84,13 +75,12 @@ def remove_optimer(request, optimer_id):
@permission_required('auth.optimer_management')
def edit_optimer(request, optimer_id):
logger.debug("edit_optimer called by user %s for optimer id %s" % (request.user, optimer_id))
op = get_object_or_404(optimer, id=optimer_id)
op = get_object_or_404(OpTimer, id=optimer_id)
if request.method == 'POST':
form = opForm(request.POST)
form = OpForm(request.POST)
logger.debug("Received POST request containing update optimer form, is valid: %s" % form.is_valid())
if form.is_valid():
auth_info = AuthServicesInfo.objects.get(user=request.user)
character = EveManager.get_character_by_id(auth_info.main_char_id)
character = request.user.profile.main_character
op.doctrine = form.cleaned_data['doctrine']
op.system = form.cleaned_data['system']
op.location = form.cleaned_data['location']
@ -115,5 +105,5 @@ def edit_optimer(request, optimer_id):
'fc': op.fc,
'details': op.details,
}
form = opForm(initial=data)
form = OpForm(initial=data)
return render(request, 'registered/optimerupdate.html', context={'form': form})

View File

@ -1,4 +1,4 @@
{% extends "public/base.html" %}
{% extends "registered/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% load i18n %}

View File

@ -1,4 +1,4 @@
{% extends "public/base.html" %}
{% extends "registered/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% load i18n %}

View File

@ -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

View File

@ -1,5 +0,0 @@
from __future__ import unicode_literals
from eveonline.tasks import run_corp_update
run_corp_update()
quit()

View File

@ -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

View 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.'))

View File

@ -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

View 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),
),
]

View File

@ -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

View File

@ -7,7 +7,6 @@ from django.conf import settings
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from eveonline.managers import EveManager
from notifications import notify
from services.modules.discord.manager import DiscordOAuthManager
from services.tasks import only_one
@ -60,6 +59,7 @@ class DiscordTasks:
return True
@staticmethod
@only_one
@app.task(bind=True, name='discord.update_groups')
def update_groups(task_self, pk):
user = User.objects.get(pk=pk)
@ -98,18 +98,21 @@ class DiscordTasks:
user = User.objects.get(pk=pk)
logger.debug("Updating discord nickname for user %s" % user)
if DiscordTasks.has_account(user):
character = EveManager.get_main_character(user)
logger.debug("Updating user %s discord nickname to %s" % (user, character.character_name))
try:
DiscordOAuthManager.update_nickname(user.discord.uid, character.character_name)
except Exception as e:
if self:
logger.exception("Discord nickname sync failed for %s, retrying in 10 mins" % user)
raise self.retry(countdown=60 * 10)
else:
# Rethrow
raise e
logger.debug("Updated user %s discord nickname." % user)
if user.profile.main_character:
character = user.profile.main_character
logger.debug("Updating user %s discord nickname to %s" % (user, character.character_name))
try:
DiscordOAuthManager.update_nickname(user.discord.uid, character.character_name)
except Exception as e:
if self:
logger.exception("Discord nickname sync failed for %s, retrying in 10 mins" % user)
raise self.retry(countdown=60 * 10)
else:
# Rethrow
raise e
logger.debug("Updated user %s discord nickname." % user)
else:
logger.debug("User %s does not have a main character" % user)
else:
logger.debug("User %s does not have a discord account" % user)

View File

@ -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)

View File

@ -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))

View File

@ -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] != "":

View File

@ -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

View File

@ -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,

View File

@ -3,16 +3,11 @@ from django.contrib.auth.decorators import login_required, permission_required
from django.shortcuts import render, redirect
from django.contrib import messages
from eveonline.managers import EveManager
from eveonline.models import EveAllianceInfo
from authentication.states import MEMBER_STATE, BLUE_STATE, NONE_STATE
from authentication.models import AuthServicesInfo
from services.forms import ServicePasswordForm
from .manager import MumbleManager
from .tasks import MumbleTasks
from .models import MumbleUser
import logging
@ -25,20 +20,11 @@ ACCESS_PERM = 'mumble.access_mumble'
@permission_required(ACCESS_PERM)
def activate_mumble(request):
logger.debug("activate_mumble called by user %s" % request.user)
authinfo = AuthServicesInfo.objects.get(user=request.user)
character = EveManager.get_main_character(request.user)
character = request.user.profile.main_character
ticker = character.corporation_ticker
if authinfo.state == BLUE_STATE:
logger.debug("Adding mumble user for blue user %s with main character %s" % (request.user, character))
# Blue members should have alliance ticker (if in alliance)
if EveAllianceInfo.objects.filter(alliance_id=character.alliance_id).exists():
alliance = EveAllianceInfo.objects.filter(alliance_id=character.alliance_id)[0]
ticker = alliance.alliance_ticker
result = MumbleManager.create_user(request.user, ticker, character.character_name, blue=True)
else:
logger.debug("Adding mumble user for user %s with main character %s" % (request.user, character))
result = MumbleManager.create_user(request.user, ticker, character.character_name)
logger.debug("Adding mumble user for %s with main character %s" % (request.user, character))
result = MumbleManager.create_user(request.user, ticker, character.character_name)
if result:
logger.debug("Updated authserviceinfo for user %s with mumble credentials. Updating groups." % request.user)

View File

@ -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[

View File

@ -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

View File

@ -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 != "":

View File

@ -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 == {}:

View File

@ -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))

View File

@ -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()

View File

@ -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