Compare commits

...

109 Commits

Author SHA1 Message Date
Basraah
2741a92d31 Version bump to v2.2.0 2019-04-14 03:07:22 +00:00
Basraah
d809902d1e Merge branch 'issue-templates' into 'master'
Create Issue Templates

See merge request allianceauth/allianceauth!1111
2019-03-12 22:16:00 +00:00
Ariel Rin
ec4232c00a Create Issue Templates 2019-03-12 22:16:00 +00:00
Basraah
dec793bfac Merge branch 'dependencies' into 'master'
Depencies fix

Closes #1150

See merge request allianceauth/allianceauth!1127
2019-03-12 20:50:00 +10:00
Basraah
fe3fe0527a Merge branch 'timer-change' into 'master'
Rename Citadels and FLEX Structures

See merge request allianceauth/allianceauth!1126
2019-03-12 10:06:53 +00:00
colcrunch
a8855e86ed Change Type [SIZE] notation for Citadels/EC/Refineries to structure names to reduce ambiguity.
Also, Added "Brand names" for the Beacon, Jammer, and Gate.
2019-03-12 10:06:53 +00:00
Basraah
179d1c38e6 Merge branch 'dj-2.1' into 'master'
Django 2.1 Compatibility

See merge request allianceauth/allianceauth!1124
2019-03-12 10:05:05 +00:00
colcrunch
287da73a4f Update StateBackend.authenticate to match ModelBackend
Also, change setup to no longer include Django 1.11
2019-03-12 10:05:05 +00:00
Basraah
e9ed917888 Merge branch 'fix_discourse_usernames' into 'master'
Send usernames as string instead of array

Closes #1149

See merge request allianceauth/allianceauth!1123
2019-03-12 10:00:52 +00:00
Basraah
70d842c971 Merge branch 'jokke_ilujo/Issue1146' into 'master'
Precent encode mumble username for connect link

See merge request allianceauth/allianceauth!1121
2019-03-12 09:58:07 +00:00
Basraah
bcda228e05 Merge branch 'mysql-docs-fix' into 'master'
Add Time Zone table instructions to Install Docs

See merge request allianceauth/allianceauth!1119
2019-03-12 09:56:20 +00:00
colcrunch
000dafc5e6 Add Time Zone table instructions to Install Docs 2019-03-12 09:56:20 +00:00
Basraah
4ea824fe71 Merge branch 'audit-log-update' into 'master'
Add datetime to Audit Log entries.

Closes #1134

See merge request allianceauth/allianceauth!1115
2019-03-12 09:53:43 +00:00
colcrunch
f72f539516 Add datetime to auditlog entries.
Also, change ordering, add pagination, and stripe the table for increased readability.

Action column now also reads "Removed" when a user is removed from a group. Note that this does not change anything on the back-end, so if you use this data for anything else, be aware that while the template is explicit, the data isn't as explicit.
2019-03-12 09:53:43 +00:00
Stephen Shirley
1b192a184f Send usernames as string instead of array
Fixes https://gitlab.com/allianceauth/allianceauth/issues/1149
2019-02-09 11:10:34 +01:00
Erno Kuvaja
0edf896b4c Precent encode mumble username for connect link
This change wraps mumble username on connect link forming with
urllib.parse.quote() to ensure that the username does not contain
unsafe reserved characters and gets passed properly to mumble.

Fixes Issue: #1146
2019-01-21 14:12:50 +00:00
Basraah
7dec4deb70 Version bump to v2.1.1 2018-12-20 22:17:04 +00:00
Basraah
d511221899 Merge branch 'flex-structures' into 'master'
Add Flex Structures to timerboard

See merge request allianceauth/allianceauth!1112
2018-12-20 22:06:01 +00:00
Basraah
d2b7de5221 Merge branch 'master' into 'master'
Update Readme and fix GitLab announcements

See merge request allianceauth/allianceauth!1113
2018-12-20 22:04:39 +00:00
colcrunch
79c5be02e2 Update Readme and fix GitLab announcements 2018-12-20 22:04:39 +00:00
Basraah
09df37438d Add missing order_by, thanks @Fundaris 2018-12-20 22:02:25 +00:00
Basraah
8561e4c6fd Merge branch 'corpstats-fix' into 'master'
update corpstats swagger.json

Closes #1139

See merge request allianceauth/allianceauth!1116
2018-12-20 21:49:35 +00:00
Aaron Kable
976cb4d988 update corpstats swagger.json 2018-12-20 08:27:56 -05:00
soratidus999
20f7d5103c Add FLEX to past timers as well as present 2018-12-01 17:43:35 +10:00
soratidus999
d049ec2832 Add Flex Structures to timerboard
New FLEX structures as per https://support.eveonline.com/hc/en-us/articles/213021829-Upwell-Structures

Cleaned up layout slightly and removed Stations as there are no longer any conquerable stations left
2018-12-01 17:26:51 +10:00
Basraah
00fe2a527e Version bump to v2.1.0 2018-11-30 07:56:54 +00:00
Basraah
f53ec3b43e Merge branch 'corputils_alliance_fix' into 'master'
None is not a valid alliance ID.

Closes #1122

See merge request allianceauth/allianceauth!1106
2018-11-30 07:54:51 +00:00
colcrunch
4d0417f114 None is not a valid alliance ID. 2018-11-30 07:54:51 +00:00
Basraah
00903b64db Merge branch 'github-to-gitlab' into 'master'
Update GitHub references to Gitlab

See merge request allianceauth/allianceauth!1110
2018-11-30 03:55:19 +00:00
Ariel Rin
a3038cad00 Update GitHub references to Gitlab 2018-11-30 03:55:19 +00:00
Basraah
ef99f1afac Merge branch 'services-market-deprecate' into 'master'
replace market docs with deprecation notice

See merge request allianceauth/allianceauth!1105
2018-11-29 23:55:37 +00:00
Basraah
cc00d4bd04 Merge branch 'services-phpbb3-docsupdate' into 'master'
Set default theme in PHPBB3, explain impact in docs

See merge request allianceauth/allianceauth!1107
2018-11-29 23:51:49 +00:00
Basraah
250f26ff6f Merge branch 'master' into 'master'
django-redis-cache does not support redis 3

See merge request allianceauth/allianceauth!1108
2018-11-29 23:51:22 +00:00
Basraah
62b786ca4a Merge branch 'zkill_fix' into 'master'
Fix srp url for zkill api

See merge request allianceauth/allianceauth!1109
2018-11-29 23:51:09 +00:00
Ariel Rin
9cfb47e658 Limit redis to 2.0 due to 3.0 incompatabilities 2018-11-29 23:12:11 +00:00
Mike
ccef27b637 Fix srp url for zkill api 2018-11-17 20:26:16 -05:00
soratidus999
8dee61fd39 Set default theme in PHPBB3, explain impact in docs
The default theme in PHPBB3 needs to be set or users cannot see the forum, this is needed because AA creates users without a theme set.

Docs explain impact and how to avoid when changing theme later on.
2018-11-15 17:45:33 +10:00
soratidus999
ae64bd0e19 replace docs with deprecation notice 2018-11-14 21:59:05 +10:00
Basraah
a75e93dbfc Version bump to v2.1b1 2018-11-14 10:55:04 +00:00
Basraah
0aa66c5729 Merge branch 'patch-1' into 'master'
limit django, django-celery-beat to compatible versions

See merge request allianceauth/allianceauth!1104
2018-11-11 08:06:39 +00:00
Ariel Rin
4c2434219d limit django, django-celery-beat to compatible versions 2018-11-11 01:55:13 +00:00
Basraah
8c65fda33b Fix incorrect hasattr 2018-10-09 23:58:35 +00:00
Basraah
14f2751bbb Fix typo 2018-10-09 19:44:11 +10:00
Basraah
d37a543c39 Update admin status to work with gitlab 2018-10-09 19:43:44 +10:00
Basraah
4947e0c483 Merge branch 'group_application_fix' into 'master'
Group Application Tweaks

See merge request allianceauth/allianceauth!1096
2018-10-09 05:15:30 +00:00
Basraah
f87c630b86 Merge branch 'fleetup-template-bootstrap-fix' into 'master'
Fixes for FleetUp templates

See merge request allianceauth/allianceauth!1100
2018-10-09 05:15:03 +00:00
Basraah
73789ea734 Prevent multiple migration leaf nodes 2018-10-09 02:15:01 +00:00
Basraah
5a16c9c495 Merge branch 'restrict_group_states' into 'master'
Restrict groups by state.

See merge request allianceauth/allianceauth!1095
2018-10-09 02:06:44 +00:00
colcrunch
9dd8357f67 Restrict groups by state. 2018-10-09 02:06:44 +00:00
Basraah
623e77a268 Avoid Dj2.1 until 1.11 depreciation issues are fixed 2018-10-07 22:45:12 +00:00
Basraah
73403b98df Merge branch 'srp_api_fix' into 'master'
Update SRP module for zKill API changes.

See merge request allianceauth/allianceauth!1102
2018-10-07 22:08:03 +00:00
colcrunch
7aa1a2f336 Update SRP module for zKill API changes. 2018-10-07 22:08:03 +00:00
Peter Pfeufer
08e42d2f56 Serving pilot avatar in fleetup character view from the right host 2018-10-06 13:02:26 +02:00
Peter Pfeufer
69248fd7bb Formatting additional informations text in operations 2018-09-29 10:34:41 +02:00
colcrunch
0af188c6ab Disallow applying to groups the user is already a member of 2018-08-29 21:28:14 -04:00
Peter Pfeufer
8b6d32d0d1 Removed unnecessary HTML comment 2018-08-11 11:09:16 +02:00
Peter Pfeufer
3c11c25d69 Corrected usage of Bootstrap classes in FleetUp templates 2018-08-11 11:03:36 +02:00
colcrunch
12e6cc63e8 Refine auto_leave check. 2018-08-05 03:34:16 -04:00
Basraah
d429c8b59a Grant srp.add_srpfleetmain access to create SRP request
See merge request allianceauth/allianceauth!1098
2018-08-05 02:24:27 +00:00
Basraah
ddd7a3551b Add Audit Log to Group Management
See merge request allianceauth/allianceauth!1089
2018-08-05 02:19:51 +00:00
Basraah
49ede92e06 Skip Teamspeak server admin groups and template groups
See merge request allianceauth/allianceauth!1093
2018-08-05 01:34:34 +00:00
Basraah
b813213328 Fix discourse group sync
See merge request allianceauth/allianceauth!1097
2018-08-04 00:06:30 +00:00
Loïc LEUILLIOT
14065b3ca9 Fix discourse group sync 2018-08-04 00:06:30 +00:00
Basraah
41f9dc490a Merge branch 'fix-fat-ship' into 'master'
Extend Ship Type field on FAT link.

See merge request allianceauth/allianceauth!1099
2018-08-03 04:57:24 +00:00
colcrunch
48d25ca73f Extend Ship Type field on FAT link.
Was not previously long enough for gold pods. Extended further for future-proofing.
2018-08-03 00:32:23 -04:00
Col Crunch
e49e04034c Imports are hard
Note to self: Read before commit
2018-08-01 23:00:31 -04:00
Col Crunch
c7860f8e5c oops 2018-08-01 22:50:44 -04:00
Col Crunch
adb982114a Actually use srp.add_srpfleetmain permission
Also adds a new @permissions_required decorator.
2018-08-01 22:38:54 -04:00
colcrunch
5b8983deac Rename Auditable group.
Its better to be explicit.
2018-07-22 20:08:16 -04:00
colcrunch
1730bc3b98 Add check for auditable groups.
To ensure functionality with other possible changes to group management.
2018-07-22 19:38:56 -04:00
Col Crunch
4374064d98 Case matters 2018-07-11 00:48:51 -04:00
Col Crunch
c1d7994045 Add setting to allow for unrestricted leaving of all groups. 2018-07-11 00:47:04 -04:00
Col Crunch
7bda367cc8 No need to allow more than one request. 2018-07-11 00:11:36 -04:00
Basraah
3de7a2ccd2 Version bump to v2.0.5 2018-07-10 02:27:32 +00:00
Basraah
9cc278df31 Merge branch 'corp_stat_fix' into 'master'
Corp Stats update to fix removal of character name endpoints

See merge request allianceauth/allianceauth!1092
2018-07-10 02:01:26 +00:00
Jamie McMillan
a0bab07e2f Fix indentation 2018-06-26 10:25:29 +01:00
randomic
149bbd92ca Skip server admin groups and template groups 2018-06-26 00:03:02 +01:00
Mike
1de3c989d7 fix tests with new endpoints (i think) 2018-06-24 17:41:27 -04:00
Mike
2e547945e2 Corp Stats update to fix removal of character name endpoints 2018-06-24 17:23:08 -04:00
Col Crunch
4d4a9a27af Merge remote-tracking branch 'allianceauth/master' 2018-06-20 16:14:02 -04:00
Basraah
5b41d0995f Update README.md badges 2018-06-06 07:12:10 +00:00
colcrunch
ab98d72022 Fix migration dependencies. 2018-06-06 07:03:57 +00:00
Unknown
8a7cd3f74d Merge remote-tracking branch 'allianceauth/master' 2018-06-06 03:00:03 -04:00
colcrunch
35cb56d6e9 Update 0009_requestlog.py 2018-06-06 06:41:56 +00:00
Basraah
a7a2ffd16b Add .gitlab-ci.yml 2018-06-06 05:46:35 +00:00
Basraah
dbeda324e0 Update tox.ini for GitLab CI 2018-06-06 05:45:23 +00:00
colcrunch
bf1fe99d98 Add Audit Log to Group Management 2018-06-04 01:45:44 -04:00
colcrunch
41429ec7c7 Merge pull request #3 from allianceauth/master
Sync
2018-06-03 20:59:17 -04:00
Adarnof
ee9ed13a66 Remove reference to depreciated bad_gateway model.
Addresses #1078

I too enjoy breaking changes with no warning. Round two.
2018-05-28 17:16:58 -04:00
Stephen Shirley
490ce286ff Add missing <tr> tags for discourse service template 2018-05-26 13:21:39 -04:00
Adarnof
099c2c0a21 Remove reference to depreciated x-user-agent header.
Addresses #1073

I too enjoy breaking changes with no warning.
2018-05-23 22:58:41 -04:00
Peter Pfeufer
46e15f7fa1 German translation corrected
At least the most obvious mistakes ...
2018-05-16 11:20:29 -04:00
Adarnof
6677e63e08 Correct resetting of permission key.
Thanks @Alf-Life
2018-05-11 10:55:56 -04:00
Adarnof
6d6a3a3d6b Allow viewing corpstats added by the user.
Order corpstats by corp name.
2018-05-10 14:25:57 -04:00
colcrunch
5006246cf1 Build TS perm key using State Information (#1044)
Build permkey with state group id
Pass user object to add_user instead of just username

Fixes #1043
2018-05-09 20:39:14 -04:00
Basraah
6187fb9b86 Timer JS fixes (#1054)
Add months to duration output
Update momentjs
Move EVE time generation function to shared source

Fixes timerboard showing EVE time as local time.
Changed to show 24 hour time.
2018-05-09 20:31:02 -04:00
Adarnof
86f57ccd56 Allow reversing service migrations.
This is probably the wrong way as we should really take care of removing the permission we added, but I don't see a reason anyone would need to migrate back that far as auth wouldn't work anymore without XML api (and even so newer installs don't have the settings referenced so permissions are not automagically added by the migration). So noop is bad but acceptable to me.

Thanks @mmolitor87
2018-05-08 10:06:58 -04:00
colcrunch
854096bac7 fix alliancelogo on corp stats page 2018-05-07 23:26:37 -04:00
Adarnof
9d2b3bb157 Include compiled messages.
It doesn't work without these if DEBUG is False. And users can't compile them outside the allianceauth source directory.

When editing translations, compile with: django-admin compilemessages --settings=allianceauth.project_template.project_name.settings.base
2018-05-02 21:42:26 -04:00
Adarnof
22bda62e59 Spanish translations courtesy of @frank1210
Fixed a few problems with translating the menu links - they had leading spaces.
2018-05-02 20:49:21 -04:00
colcrunch
c8ad1dcc7a Merge pull request #2 from allianceauth/master
sync
2018-05-02 20:01:42 -04:00
Adarnof
7212a7a328 Example supervisor config for authenticator. Ensure ICE is active in config. 2018-05-01 16:40:37 -04:00
Adarnof
f6b1b7b6bb Do not check mains when user has no profile.
This can occur when a user is being deleted: Django deletes the UserProfile, followed by the CharacterOwnerships which triggers the main check. As the user doesn't have a profile it explodes.

Thanks @Slevinator
2018-04-30 17:29:06 -04:00
Adarnof
53a9d72c4a Correct reversing states back to groups. 2018-04-30 17:24:31 -04:00
Adarnof
ca10fbcde5 Translate Member/Blue to custom state names.
Closes #1037
2018-04-25 17:20:28 -04:00
randomic
b4d33e5dfc Fix retry logic being suppressed by try block (#1035) 2018-04-24 11:53:13 -04:00
Adarnof
37bed989f1 Requires mariadb-shared for mysqlclient on centos.
Thanks @rlayne
2018-04-22 12:50:22 -04:00
colcrunch
0b7520e3b1 Fix celerybeat task in ts3 config. 2018-03-22 15:23:52 -04:00
colcrunch
48c8ccfe97 Merge pull request #1 from allianceauth/master
sync
2018-03-22 15:20:48 -04:00
89 changed files with 3382 additions and 1104 deletions

5
.gitignore vendored
View File

@@ -42,7 +42,6 @@ nosetests.xml
coverage.xml coverage.xml
# Translations # Translations
*.mo
*.pot *.pot
# Django stuff: # Django stuff:
@@ -63,3 +62,7 @@ celerybeat-schedule
#pycharm #pycharm
.idea/* .idea/*
/nbproject/
#gitlab configs
.gitlab/

33
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,33 @@
# Official language image. Look for the different tagged releases at:
# https://hub.docker.com/r/library/python/tags/
.job_template: &job_definition
# Change pip's cache directory to be inside the project directory since we can
# only cache local items.
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache"
# Pip's cache doesn't store the python packages
# https://pip.pypa.io/en/stable/reference/pip_install/#caching
#
# If you want to also cache the installed packages, you have to install
# them in a virtualenv and cache it as well.
cache:
paths:
- .cache/pip
- venv/
before_script:
- python -V # Print out python version for debugging
- pip install virtualenv tox
- virtualenv venv
- source venv/bin/activate
coverage: '/TOTAL.+ ([0-9]{1,3}%)/'
py36-dj20:
<<: *job_definition
image: python:3.6-stretch
script:
- export TOXENV=py36-dj20
- tox

View File

@@ -0,0 +1,14 @@
# Bug
- I have searched [issues](https://gitlab.com/allianceauth/allianceauth/issues?scope=all&utf8=%E2%9C%93&state=all) (Y/N):
- What Version of Alliance Auth:
- What Operating System:
- Version of other components relevant to issue eg. Service, Database:
Please include a brief description of your issue here.
Please include steps to reproduce the issue
Please include any tracebacks or logs
Please include the results of the command `pip list`

View File

@@ -0,0 +1,7 @@
# Feature Request
- Describe the feature are you requesting.
- Is this a Service (external integration), a Module (Alliance Auth extension) or an enhancement to an existing service/module.
- Describe why its useful to you or others.

View File

@@ -1,28 +1,29 @@
Alliance Auth Alliance Auth
============ ============
[![Join the chat at https://gitter.im/R4stl1n/allianceauth](https://badges.gitter.im/R4stl1n/allianceauth.svg)](https://gitter.im/R4stl1n/allianceauth?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Chat on Discord](https://img.shields.io/discord/399006117012832262.svg)](https://discord.gg/fjnHAmk)
[![Documentation Status](https://readthedocs.org/projects/allianceauth/badge/?version=latest)](http://allianceauth.readthedocs.io/?badge=latest) [![Documentation Status](https://readthedocs.org/projects/allianceauth/badge/?version=latest)](http://allianceauth.readthedocs.io/?badge=latest)
[![Build Status](https://travis-ci.org/allianceauth/allianceauth.svg?branch=master)](https://travis-ci.org/allianceauth/allianceauth) [![pipeline status](https://gitlab.com/allianceauth/allianceauth/badges/master/pipeline.svg)](https://gitlab.com/allianceauth/allianceauth/commits/master)
[![Coverage Status](https://coveralls.io/repos/github/allianceauth/allianceauth/badge.svg?branch=master)](https://coveralls.io/github/allianceauth/allianceauth?branch=master) [![coverage report](https://gitlab.com/allianceauth/allianceauth/badges/master/coverage.svg)](https://gitlab.com/allianceauth/allianceauth/commits/master)
An auth system for EVE Online to help in-game organizations manage online service access. An auth system for EVE Online to help in-game organizations manage online service access.
[Read the docs here.](http://allianceauth.rtfd.io) [Read the docs here.](http://allianceauth.rtfd.io)
[Get help on gitter](https://gitter.im/R4stl1n/allianceauth) or submit an Issue. [Get help on Discord](https://discord.gg/fjnHAmk) or submit an Issue.
Active Developers: Active Developers:
- [Adarnof](https://github.com/adarnof/) - [Adarnof](https://gitlab.com/adarnof/)
- [Basraah](https://github.com/basraah/) - [Basraah](https://gitlab.com/basraah/)
Beta Testers / Bug Fixers: Beta Testers / Bug Fixers:
- [ghoti](https://github.com/ghoti/) - [ghoti](https://gitlab.com/ChainsawMcGinny/)
- [mmolitor87](https://github.com/mmolitor87/) - [mmolitor87](https://gitlab.com/mmolitor87/)
- [TargetZ3R0](https://github.com/TargetZ3R0) - [TargetZ3R0](https://github.com/TargetZ3R0)
- [kaezon](https://github.com/kaezon/) - [kaezon](https://github.com/kaezon/)
- [orbitroom](https://github.com/orbitroom/) - [orbitroom](https://github.com/orbitroom/)
@@ -31,4 +32,4 @@ Beta Testers / Bug Fixers:
Special thanks to [Nikdoof](https://github.com/nikdoof/), as his [auth](https://github.com/nikdoof/test-auth) was the foundation for the original work on this project. Special thanks to [Nikdoof](https://github.com/nikdoof/), as his [auth](https://github.com/nikdoof/test-auth) was the foundation for the original work on this project.
### Contributing ### Contributing
Make sure you have signed the [License Agreement](https://developers.eveonline.com/resource/license-agreement) by logging in at [https://developers.eveonline.com](https://developers.eveonline.com) before submitting any pull requests. Make sure you have signed the [License Agreement](https://developers.eveonline.com/resource/license-agreement) by logging in at [https://developers.eveonline.com](https://developers.eveonline.com) before submitting any pull requests.

View File

@@ -1,7 +1,6 @@
# This will make sure the app is always imported when # This will make sure the app is always imported when
# Django starts so that shared_task will use this app. # Django starts so that shared_task will use this app.
__version__ = '2.0.0' __version__ = '2.2.0'
NAME = 'Alliance Auth v%s' % __version__ NAME = 'Alliance Auth v%s' % __version__
default_app_config = 'allianceauth.apps.AllianceAuthConfig' default_app_config = 'allianceauth.apps.AllianceAuthConfig'

View File

@@ -27,7 +27,7 @@ class StateBackend(ModelBackend):
user_obj._perm_cache.update(self.get_state_permissions(user_obj)) user_obj._perm_cache.update(self.get_state_permissions(user_obj))
return user_obj._perm_cache return user_obj._perm_cache
def authenticate(self, token=None): def authenticate(self, request=None, token=None, **credentials):
if not token: if not token:
return None return None
try: try:

View File

@@ -1,4 +1,6 @@
from django.conf.urls import include from django.conf.urls import include
from django.contrib.auth.decorators import user_passes_test
from django.core.exceptions import PermissionDenied
from functools import wraps from functools import wraps
from django.shortcuts import redirect from django.shortcuts import redirect
from django.contrib import messages from django.contrib import messages
@@ -35,3 +37,32 @@ def main_character_required(view_func):
messages.error(request, _('A main character is required to perform that action. Add one below.')) messages.error(request, _('A main character is required to perform that action. Add one below.'))
return redirect('authentication:dashboard') return redirect('authentication:dashboard')
return login_required(_wrapped_view) return login_required(_wrapped_view)
def permissions_required(perm, login_url=None, raise_exception=False):
"""
Decorator for views that checks whether a user has a particular permission
enabled, redirecting to the log-in page if necessary.
If the raise_exception parameter is given the PermissionDenied exception
is raised.
This decorator is identical to the django permission_required except it
allows for passing a tuple/list of perms that will return true if any one
of them is present.
"""
def check_perms(user):
if isinstance(perm, str):
perms = (perm,)
else:
perms = perm
# First check if the user has the permission (even anon users)
for perm_ in perms:
perm_ = (perm_,)
if user.has_perms(perm_):
return True
# In case the 403 handler should be called raise the exception
if raise_exception:
raise PermissionDenied
# As the last resort, show the login form
return False
return user_passes_test(check_perms, login_url=login_url)

View File

@@ -43,7 +43,7 @@ def create_member_group(apps, schema_editor):
member_state_name = getattr(settings, 'DEFAULT_AUTH_GROUP', 'Member') member_state_name = getattr(settings, 'DEFAULT_AUTH_GROUP', 'Member')
try: try:
g = Group.objects.get(name=member_state_name) g, _ = Group.objects.get_or_create(name=member_state_name)
# move permissions back # move permissions back
state = State.objects.get(name=member_state_name) state = State.objects.get(name=member_state_name)
[g.permissions.add(p.pk) for p in state.permissions.all()] [g.permissions.add(p.pk) for p in state.permissions.all()]
@@ -51,7 +51,7 @@ def create_member_group(apps, schema_editor):
# move users back # move users back
for profile in state.userprofile_set.all().select_related('user'): for profile in state.userprofile_set.all().select_related('user'):
profile.user.groups.add(g.pk) profile.user.groups.add(g.pk)
except (Group.DoesNotExist, State.DoesNotExist): except State.DoesNotExist:
pass pass
@@ -67,7 +67,7 @@ def create_blue_state(apps, schema_editor):
# move group permissions to state # move group permissions to state
g = Group.objects.get(name=blue_state_name) g = Group.objects.get(name=blue_state_name)
[s.permissions.add(p.pk) for p in g.permissions.all()] [s.permissions.add(p.pk) for p in g.permissions.all()]
g.permissions.clear() g.delete()
except Group.DoesNotExist: except Group.DoesNotExist:
pass pass
@@ -84,7 +84,7 @@ def create_blue_group(apps, schema_editor):
blue_state_name = getattr(settings, 'DEFAULT_BLUE_GROUP', 'Blue') blue_state_name = getattr(settings, 'DEFAULT_BLUE_GROUP', 'Blue')
try: try:
g = Group.objects.get(name=blue_state_name) g, _ = Group.objects.get_or_create(name=blue_state_name)
# move permissions back # move permissions back
state = State.objects.get(name=blue_state_name) state = State.objects.get(name=blue_state_name)
[g.permissions.add(p.pk) for p in state.permissions.all()] [g.permissions.add(p.pk) for p in state.permissions.all()]
@@ -92,7 +92,7 @@ def create_blue_group(apps, schema_editor):
# move users back # move users back
for profile in state.userprofile_set.all().select_related('user'): for profile in state.userprofile_set.all().select_related('user'):
profile.user.groups.add(g.pk) profile.user.groups.add(g.pk)
except (Group.DoesNotExist, State.DoesNotExist): except State.DoesNotExist:
pass pass
@@ -133,15 +133,24 @@ def create_profiles(apps, schema_editor):
auth['n'] == 1 and EveCharacter.objects.filter(character_id=auth['main_char_id']).exists()] 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') auths = AuthServicesInfo.objects.filter(main_char_id__in=unique_mains).select_related('user')
blue_state_name = getattr(settings, 'DEFAULT_BLUE_GROUP', 'Blue')
member_state_name = getattr(settings, 'DEFAULT_AUTH_GROUP', 'Member')
states = {
'Member': State.objects.get(name=member_state_name),
'Blue': State.objects.get(name=blue_state_name),
}
guest_state = State.objects.get(name='Guest')
for auth in auths: for auth in auths:
# carry states and mains forward # carry states and mains forward
state = State.objects.get(name=auth.state if auth.state else 'Guest') state = states.get(auth.state, guest_state)
char = EveCharacter.objects.get(character_id=auth.main_char_id) char = EveCharacter.objects.get(character_id=auth.main_char_id)
UserProfile.objects.create(user=auth.user, state=state, main_character=char) UserProfile.objects.create(user=auth.user, state=state, main_character=char)
for auth in AuthServicesInfo.objects.exclude(main_char_id__in=unique_mains).select_related('user'): for auth in AuthServicesInfo.objects.exclude(main_char_id__in=unique_mains).select_related('user'):
# prepare empty profiles # prepare empty profiles
state = State.objects.get(name='Guest') UserProfile.objects.create(user=auth.user, state=guest_state)
UserProfile.objects.create(user=auth.user, state=state)
def recreate_authservicesinfo(apps, schema_editor): def recreate_authservicesinfo(apps, schema_editor):
@@ -149,6 +158,14 @@ def recreate_authservicesinfo(apps, schema_editor):
UserProfile = apps.get_model('authentication', 'UserProfile') UserProfile = apps.get_model('authentication', 'UserProfile')
User = apps.get_model('auth', 'User') User = apps.get_model('auth', 'User')
blue_state_name = getattr(settings, 'DEFAULT_BLUE_GROUP', 'Blue')
member_state_name = getattr(settings, 'DEFAULT_AUTH_GROUP', 'Member')
states = {
member_state_name: 'Member',
blue_state_name: 'Blue',
}
# recreate all missing AuthServicesInfo models # recreate all missing AuthServicesInfo models
AuthServicesInfo.objects.bulk_create([AuthServicesInfo(user_id=u.pk) for u in User.objects.all()]) AuthServicesInfo.objects.bulk_create([AuthServicesInfo(user_id=u.pk) for u in User.objects.all()])
@@ -159,8 +176,8 @@ def recreate_authservicesinfo(apps, schema_editor):
# repopulate states we understand # repopulate states we understand
for profile in UserProfile.objects.exclude(state__name='Guest').filter( for profile in UserProfile.objects.exclude(state__name='Guest').filter(
state__name__in=['Member', 'Blue']).select_related('user', 'state'): state__name__in=[member_state_name, blue_state_name]).select_related('user', 'state'):
AuthServicesInfo.objects.update_or_create(user=profile.user, defaults={'state': profile.state.name}) AuthServicesInfo.objects.update_or_create(user=profile.user, defaults={'state': states[profile.state.name]})
def disable_passwords(apps, schema_editor): def disable_passwords(apps, schema_editor):

View File

@@ -103,12 +103,16 @@ def record_character_ownership(sender, instance, created, *args, **kwargs):
@receiver(pre_delete, sender=CharacterOwnership) @receiver(pre_delete, sender=CharacterOwnership)
def validate_main_character(sender, instance, *args, **kwargs): def validate_main_character(sender, instance, *args, **kwargs):
if instance.user.profile.main_character == instance.character: try:
logger.info("Ownership of a main character {0} has been revoked. Resetting {1} main character.".format( if instance.user.profile.main_character == instance.character:
instance.character, instance.user)) logger.info("Ownership of a main character {0} has been revoked. Resetting {1} main character.".format(
# clear main character as user no longer owns them instance.character, instance.user))
instance.user.profile.main_character = None # clear main character as user no longer owns them
instance.user.profile.save() instance.user.profile.main_character = None
instance.user.profile.save()
except UserProfile.DoesNotExist:
# a user is being deleted
pass
@receiver(post_delete, sender=Token) @receiver(post_delete, sender=Token)

View File

@@ -119,7 +119,7 @@ class BackendTestCase(TestCase):
def test_authenticate_character_record(self): def test_authenticate_character_record(self):
t = Token(character_id=self.unclaimed_character.character_id, character_name=self.unclaimed_character.character_name, character_owner_hash='4') t = Token(character_id=self.unclaimed_character.character_id, character_name=self.unclaimed_character.character_name, character_owner_hash='4')
record = OwnershipRecord.objects.create(user=self.old_user, character=self.unclaimed_character, owner_hash='4') record = OwnershipRecord.objects.create(user=self.old_user, character=self.unclaimed_character, owner_hash='4')
user = StateBackend().authenticate(t) user = StateBackend().authenticate(token=t)
self.assertEqual(user, self.old_user) self.assertEqual(user, self.old_user)
self.assertTrue(CharacterOwnership.objects.filter(owner_hash='4', user=self.old_user).exists()) self.assertTrue(CharacterOwnership.objects.filter(owner_hash='4', user=self.old_user).exists())
self.assertTrue(user.profile.main_character) self.assertTrue(user.profile.main_character)

View File

@@ -1,5 +1,5 @@
from allianceauth.services.hooks import MenuItemHook, UrlHook from allianceauth.services.hooks import MenuItemHook, UrlHook
from django.utils.translation import ugettext_lazy as _
from allianceauth import hooks from allianceauth import hooks
from allianceauth.corputils import urls from allianceauth.corputils import urls
@@ -7,7 +7,7 @@ from allianceauth.corputils import urls
class CorpStats(MenuItemHook): class CorpStats(MenuItemHook):
def __init__(self): def __init__(self):
MenuItemHook.__init__(self, MenuItemHook.__init__(self,
'Corporation Stats', _('Corporation Stats'),
'fa fa-share-alt fa-fw', 'fa fa-share-alt fa-fw',
'corputils:view', 'corputils:view',
navactive=['corputils:']) navactive=['corputils:'])

View File

@@ -16,10 +16,16 @@ class CorpStatsQuerySet(models.QuerySet):
assert char assert char
# build all accepted queries # build all accepted queries
queries = [models.Q(token__user=user)] queries = [models.Q(token__user=user)]
if user.has_perm('corputils.view_corp_corpstats'):
queries.append(models.Q(corp__corporation_id=char.corporation_id))
if user.has_perm('corputils.view_alliance_corpstats'): if user.has_perm('corputils.view_alliance_corpstats'):
queries.append(models.Q(corp__alliance__alliance_id=char.alliance_id)) if char.alliance_id is not None:
queries.append(models.Q(corp__alliance__alliance_id=char.alliance_id))
else:
queries.append(models.Q(corp__corporation_id=char.corporation_id))
if user.has_perm('corputils.view_corp_corpstats'):
if user.has_perm('corputils.view_alliance_corpstats'):
pass
else:
queries.append(models.Q(corp__corporation_id=char.corporation_id))
if user.has_perm('corputils.view_state_corpstats'): if user.has_perm('corputils.view_state_corpstats'):
queries.append(models.Q(corp__in=user.profile.state.member_corporations.all())) queries.append(models.Q(corp__in=user.profile.state.member_corporations.all()))
queries.append(models.Q(corp__alliance__in=user.profile.state.member_alliances.all())) queries.append(models.Q(corp__alliance__in=user.profile.state.member_alliances.all()))

View File

@@ -12,6 +12,16 @@ from allianceauth.notifications import notify
from allianceauth.corputils.managers import CorpStatsManager from allianceauth.corputils.managers import CorpStatsManager
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json') SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json')
"""
Swagger spec operations:
Character
get_characters_character_id
get_corporations_corporation_id_members
Universe
post_universe_names
"""
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -47,11 +57,11 @@ class CorpStats(models.Model):
# the swagger spec doesn't have a maxItems count # the swagger spec doesn't have a maxItems count
# manual testing says we can do over 350, but let's not risk it # manual testing says we can do over 350, but let's not risk it
member_id_chunks = [member_ids[i:i + 255] for i in range(0, len(member_ids), 255)] member_id_chunks = [member_ids[i:i + 255] for i in range(0, len(member_ids), 255)]
member_name_chunks = [c.Character.get_characters_names(character_ids=id_chunk).result() for id_chunk in member_name_chunks = [c.Universe.post_universe_names(ids=id_chunk).result() for id_chunk in
member_id_chunks] member_id_chunks]
member_list = {} member_list = {}
for name_chunk in member_name_chunks: for name_chunk in member_name_chunks:
member_list.update({m['character_id']: m['character_name'] for m in name_chunk}) member_list.update({m['id']: m['name'] for m in name_chunk})
# bulk create new member models # bulk create new member models
missing_members = [m_id for m_id in member_ids if missing_members = [m_id for m_id in member_ids if

File diff suppressed because one or more lines are too long

View File

@@ -11,7 +11,7 @@
{% if corpstats.corp.alliance %}{% else %}col-lg-offset-3{% endif %}"><img {% if corpstats.corp.alliance %}{% else %}col-lg-offset-3{% endif %}"><img
class="ra-avatar" src="{{ corpstats.corp.logo_url_128 }}"></td> class="ra-avatar" src="{{ corpstats.corp.logo_url_128 }}"></td>
{% if corpstats.corp.alliance %} {% if corpstats.corp.alliance %}
<td class="text-center col-lg-6"><img class="ra-avatar" src="{{ corpstats.alliance.logo_url_128 }}"> <td class="text-center col-lg-6"><img class="ra-avatar" src="{{ corpstats.corp.alliance.logo_url_128 }}">
</td> </td>
{% endif %} {% endif %}
</tr> </tr>
@@ -202,4 +202,4 @@
}); });
}); });
{% endblock %} {% endblock %}

View File

@@ -86,7 +86,7 @@ class CorpStatsUpdateTestCase(TestCase):
def test_update_add_member(self, SwaggerClient): def test_update_add_member(self, SwaggerClient):
SwaggerClient.from_spec.return_value.Character.get_characters_character_id.return_value.result.return_value = {'corporation_id': 2} SwaggerClient.from_spec.return_value.Character.get_characters_character_id.return_value.result.return_value = {'corporation_id': 2}
SwaggerClient.from_spec.return_value.Corporation.get_corporations_corporation_id_members.return_value.result.return_value = [1] SwaggerClient.from_spec.return_value.Corporation.get_corporations_corporation_id_members.return_value.result.return_value = [1]
SwaggerClient.from_spec.return_value.Character.get_characters_names.return_value.result.return_value = [{'character_id': 1, 'character_name': 'test character'}] SwaggerClient.from_spec.return_value.Universe.post_universe_names.return_value.result.return_value = [{'id': 1, 'name': 'test character'}]
self.corpstats.update() self.corpstats.update()
self.assertTrue(CorpMember.objects.filter(character_id='1', character_name='test character', corpstats=self.corpstats).exists()) self.assertTrue(CorpMember.objects.filter(character_id='1', character_name='test character', corpstats=self.corpstats).exists())
@@ -95,7 +95,7 @@ class CorpStatsUpdateTestCase(TestCase):
CorpMember.objects.create(character_id='2', character_name='old test character', corpstats=self.corpstats) CorpMember.objects.create(character_id='2', character_name='old test character', corpstats=self.corpstats)
SwaggerClient.from_spec.return_value.Character.get_characters_character_id.return_value.result.return_value = {'corporation_id': 2} SwaggerClient.from_spec.return_value.Character.get_characters_character_id.return_value.result.return_value = {'corporation_id': 2}
SwaggerClient.from_spec.return_value.Corporation.get_corporations_corporation_id_members.return_value.result.return_value = [1] SwaggerClient.from_spec.return_value.Corporation.get_corporations_corporation_id_members.return_value.result.return_value = [1]
SwaggerClient.from_spec.return_value.Character.get_characters_names.return_value.result.return_value = [{'character_id': 1, 'character_name': 'test character'}] SwaggerClient.from_spec.return_value.Universe.post_universe_names.return_value.result.return_value = [{'id': 1, 'name': 'test character'}]
self.corpstats.update() self.corpstats.update()
self.assertFalse(CorpMember.objects.filter(character_id='2', corpstats=self.corpstats).exists()) self.assertFalse(CorpMember.objects.filter(character_id='2', corpstats=self.corpstats).exists())

View File

@@ -13,11 +13,17 @@ from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo
from .models import CorpStats from .models import CorpStats
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json') SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json')
"""
Swagger spec operations:
get_characters_character_id
"""
def access_corpstats_test(user): def access_corpstats_test(user):
return user.has_perm('corputils.view_corp_corpstats') or user.has_perm( return user.has_perm('corputils.view_corp_corpstats') or user.has_perm(
'corputils.view_alliance_corpstats') or user.has_perm('corputils.view_state_corpstats') 'corputils.view_alliance_corpstats') or user.has_perm('corputils.view_state_corpstats') or user.has_perm(
'corputils.add_corpstats')
@login_required @login_required
@@ -62,7 +68,7 @@ def corpstats_view(request, corp_id=None):
corpstats = get_object_or_404(CorpStats, corp=corp) corpstats = get_object_or_404(CorpStats, corp=corp)
# get available models # get available models
available = CorpStats.objects.visible_to(request.user) available = CorpStats.objects.visible_to(request.user).order_by('corp__corporation_name')
# ensure we can see the requested model # ensure we can see the requested model
if corpstats and corpstats not in available: if corpstats and corpstats not in available:

View File

@@ -4,6 +4,16 @@ import logging
import os import os
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json') SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json')
"""
Swagger spec operations:
get_alliances_alliance_id
get_alliances_alliance_id_corporations
get_corporations_corporation_id
get_characters_character_id
get_universe_types_type_id
"""
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

File diff suppressed because one or more lines are too long

View File

@@ -1,12 +1,12 @@
from . import urls from . import urls
from django.utils.translation import ugettext_lazy as _
from allianceauth import hooks from allianceauth import hooks
from allianceauth.services.hooks import MenuItemHook, UrlHook from allianceauth.services.hooks import MenuItemHook, UrlHook
@hooks.register('menu_item_hook') @hooks.register('menu_item_hook')
def register_menu(): def register_menu():
return MenuItemHook('Fleet Activity Tracking', 'fa fa-users fa-lightbulb-o fa-fw', 'fatlink:view', return MenuItemHook(_('Fleet Activity Tracking'), 'fa fa-users fa-lightbulb-o fa-fw', 'fatlink:view',
navactive=['fatlink:']) navactive=['fatlink:'])

View File

@@ -0,0 +1,18 @@
# Generated by Django 2.0.6 on 2018-08-03 04:30
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fleetactivitytracking', '0005_remove_fat_name'),
]
operations = [
migrations.AlterField(
model_name='fat',
name='shiptype',
field=models.CharField(max_length=100),
),
]

View File

@@ -24,7 +24,7 @@ class Fat(models.Model):
character = models.ForeignKey(EveCharacter, on_delete=models.CASCADE) character = models.ForeignKey(EveCharacter, on_delete=models.CASCADE)
fatlink = models.ForeignKey(Fatlink, on_delete=models.CASCADE) fatlink = models.ForeignKey(Fatlink, on_delete=models.CASCADE)
system = models.CharField(max_length=30) system = models.CharField(max_length=30)
shiptype = models.CharField(max_length=30) shiptype = models.CharField(max_length=100)
station = models.CharField(max_length=125) station = models.CharField(max_length=125)
user = models.ForeignKey(User, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE)

File diff suppressed because one or more lines are too long

View File

@@ -22,6 +22,16 @@ from allianceauth.eveonline.models import EveCharacter
from allianceauth.eveonline.models import EveCorporationInfo from allianceauth.eveonline.models import EveCorporationInfo
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json') SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json')
"""
Swagger spec operations:
get_characters_character_id_location
get_characters_character_id_ship
get_universe_systems_system_id
get_universe_stations_station_id
get_universe_structures_structure_id
"""
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -112,7 +122,7 @@ def fatlink_statistics_corp_view(request, corpid, year=None, month=None):
start_of_next_month = first_day_of_next_month(year, month) start_of_next_month = first_day_of_next_month(year, month)
start_of_previous_month = first_day_of_previous_month(year, month) start_of_previous_month = first_day_of_previous_month(year, month)
fat_stats = {} fat_stats = {}
corp_members = CharacterOwnership.objects.filter(character__corporation_id=corpid).values('user_id').distinct() corp_members = CharacterOwnership.objects.filter(character__corporation_id=corpid).order_by('user_id').values('user_id').distinct()
for member in corp_members: for member in corp_members:
try: try:

View File

@@ -15,7 +15,7 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div class="col-lg-6"> <div class="col-lg-6">
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-condensed table-hover table-striped"> <table class="table table-condensed table-hover table-striped">
<tr> <tr>
<th class="col-md-1"></th> <th class="col-md-1"></th>
@@ -26,7 +26,7 @@
{% for char_name, user_id in member_list %} {% for char_name, user_id in member_list %}
<tr> <tr>
<td> <td>
<img src="http://image.eveonline.com/Character/{{ user_id.char_id }}_32.jpg" class="img-circle"> <img src="https://imageserver.eveonline.com/Character/{{ user_id.char_id }}_32.jpg" class="img-circle">
</td> </td>
<td> <td>
<p>{{ user_id.char_name }}</p> <p>{{ user_id.char_name }}</p>

View File

@@ -8,12 +8,12 @@
{% block content %} {% block content %}
<div class="col-lg-12"> <div class="col-lg-12">
{% include "fleetup/menu.html" %} {% include "fleetup/menu.html" %}
<div class="panel"> <div>
{% for a, j in doctrine.items %} {% for a, j in doctrine.items %}
{% regroup j.Data|dictsort:"Role" by Role as role_list %} {% regroup j.Data|dictsort:"Role" by Role as role_list %}
{% for Role in role_list %} {% for Role in role_list %}
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h3 class="panel-title"><b>{{ Role.grouper }}</b></h3> <h3 class="panel-title"><b>{{ Role.grouper }}</b></h3>
@@ -50,7 +50,7 @@
{% load humanize %}{{ item.EstPrice|intword }} {% load humanize %}{{ item.EstPrice|intword }}
</td> </td>
<td> <td>
{% for categories in item.Categories %} {% for categories in item.Categories %}
{{ categories }}, {{ categories }},
{% endfor %} {% endfor %}
</td> </td>

View File

@@ -8,12 +8,12 @@
{% block content %} {% block content %}
<div class="col-lg-12"> <div class="col-lg-12">
{% include "fleetup/menu.html" %} {% include "fleetup/menu.html" %}
<div class="panel"> <div>
{% if doctrines_list %} {% if doctrines_list %}
{% for a, j in doctrines_list.items %} {% for a, j in doctrines_list.items %}
{% regroup j|dictsort:"FolderName" by FolderName as folder_list %} {% regroup j|dictsort:"FolderName" by FolderName as folder_list %}
{% for FolderName in folder_list %} {% for FolderName in folder_list %}
<div class="col-lg-8"> <div>
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h3 class="panel-title"><b>{{ FolderName.grouper }}</b></h3> <h3 class="panel-title"><b>{{ FolderName.grouper }}</b></h3>
@@ -29,11 +29,11 @@
<th class="col-lg-2">Note</th>--> <th class="col-lg-2">Note</th>-->
</tr> </tr>
{% for item in FolderName.list %} {% for item in FolderName.list %}
<tr> <tr>
<td> <td>
<a href="{% url 'fleetup:doctrine' item.DoctrineId %}"><img src="https://image.eveonline.com/InventoryType/{{ item.IconId }}_32.png"></a> <a href="{% url 'fleetup:doctrine' item.DoctrineId %}"><img src="https://image.eveonline.com/InventoryType/{{ item.IconId }}_32.png"></a>
</td> </td>
<td> <td>
{{ item.Name }} {{ item.Name }}
</td> </td>

View File

@@ -8,9 +8,9 @@
{% block content %} {% block content %}
<div class="col-lg-12"> <div class="col-lg-12">
{% include "fleetup/menu.html" %} {% include "fleetup/menu.html" %}
<div class="tab-content"> <div class="tab-content row">
<div id="fit" class="tab-pane fade in active"> <div id="fit" class="tab-pane fade in active">
<div class="col-lg-3"> <div class="col-lg-4">
{% for x, y in fitting_data.items %} {% for x, y in fitting_data.items %}
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
@@ -18,22 +18,24 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
{% for doctrin in y.Doctrines %} {% for doctrin in y.Doctrines %}
<h4>{{ doctrin.Name }}</h4> <div class="clearfix">
<div class="col-lg-12"> <h4>{{ doctrin.Name }}</h4>
<p>{% trans "Role in doctrine:" %} {{ doctrin.Role }}</p> <div class="col-lg-12">
</div> <p>{% trans "Role in doctrine:" %} {{ doctrin.Role }}</p>
<div class="col-lg-4"> </div>
<p>{% trans "Priority:" %}</p> <div class="col-lg-4">
</div> <p>{% trans "Priority:" %}</p>
<div class="col-lg-8"> </div>
<div class="progress"> <div class="col-lg-8">
<div class="progress-bar progress-bar-striped" role="progressbar" aria-valuenow="{{ doctrin.Priority }}" aria-valuemin="0" aria-valuemax="5" style="width: {% widthratio doctrin.Priority 5 100 %}%;"> <div class="progress">
{{ doctrin.Priority }}/5 <div class="progress-bar progress-bar-striped" role="progressbar" aria-valuenow="{{ doctrin.Priority }}" aria-valuemin="0" aria-valuemax="5" style="width: {% widthratio doctrin.Priority 5 100 %}%;">
{{ doctrin.Priority }}/5
</div>
</div> </div>
</div> </div>
</div> <div class="pull-right">
<div class="pull-right"> <a class="btn btn-primary" href="{% url 'fleetup:doctrine' doctrin.DoctrineId %}">{% trans "See doctrine" %}</a>
<a class="btn btn-primary" href="{% url 'fleetup:doctrine' doctrin.DoctrineId %}">{% trans "See doctrine" %}</a> </div>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
@@ -56,10 +58,10 @@
<div class="panel-body"> <div class="panel-body">
<div class="list-group"> <div class="list-group">
{% for arbit, orbit in doctrines_list.items %} {% for arbit, orbit in doctrines_list.items %}
{% for fitting in orbit.Data %} {% for fitting in orbit.Data %}
<a href="{% url 'fleetup:fitting' fitting.FittingId %}" class="list-group-item"> <a href="{% url 'fleetup:fitting' fitting.FittingId %}" class="list-group-item">
<h4 class="list-group-item-heading">{{ fitting.Name }}<span class="pull-right"><img src="https://image.eveonline.com/InventoryType/{{ fitting.EveTypeId }}_32.png" class="img-circle"></span></h4> <h4 class="list-group-item-heading">{{ fitting.Name }}<span class="pull-right"><img src="https://image.eveonline.com/InventoryType/{{ fitting.EveTypeId }}_32.png" class="img-circle"></span></h4>
<p class="list-group-item-heading">{{ fitting.Role }} - {{ fitting.ShipType }}</p> <p class="list-group-item-heading">{{ fitting.Role }} - {{ fitting.ShipType }}</p>
</a> </a>
@@ -107,8 +109,8 @@
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
<div class="col-lg-3"> <div class="col-lg-4">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h3 class="panel-title">{% trans "EFT/Export" %}</h3> <h3 class="panel-title">{% trans "EFT/Export" %}</h3>

View File

@@ -20,11 +20,11 @@
<th class="col-md-2">{% trans "Categories" %}</th> <th class="col-md-2">{% trans "Categories" %}</th>
</tr> </tr>
{% for id, fittings in fitting_list %} {% for id, fittings in fitting_list %}
<tr> <tr>
<td> <td>
<a href="{% url 'fleetup:fitting' fittings.fitting_id %}"><img src="https://image.eveonline.com/InventoryType/{{ fittings.icon_id }}_32.png"></a> <a href="{% url 'fleetup:fitting' fittings.fitting_id %}"><img src="https://image.eveonline.com/InventoryType/{{ fittings.icon_id }}_32.png"></a>
</td> </td>
<td> <td>
{{ fittings.name }} {{ fittings.name }}
</td> </td>
@@ -38,12 +38,12 @@
{% load humanize %}{{ fittings.estimated|intword }} {% load humanize %}{{ fittings.estimated|intword }}
</td> </td>
<td> <td>
{% for categories in fittings.categories %} {% for categories in fittings.categories %}
{{ categories }}, {{ categories }},
{% endfor %} {% endfor %}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
{% else %} {% else %}

View File

@@ -8,15 +8,15 @@
{% block content %} {% block content %}
<div class="col-lg-12"> <div class="col-lg-12">
{% include "fleetup/menu.html" %} {% include "fleetup/menu.html" %}
<div class="panel"> <div>
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"><a data-toggle="tab" href="#operations">{% trans "Operations" %}</a></li> <li class="active"><a data-toggle="tab" href="#operations">{% trans "Operations" %}</a></li>
<li><a data-toggle="tab" href="#timers">{% trans "Timers" %}</a></li> <li><a data-toggle="tab" href="#timers">{% trans "Timers" %}</a></li>
</ul> </ul>
<div class="tab-content"> <div class="tab-content row">
<div id="operations" class="tab-pane fade in active"> <div id="operations" class="tab-pane fade in active">
<div class="col-lg-7"> <div class="col-lg-8">
{% if operations_list %} {% if operations_list %}
{% for subject, start in operations_list %} {% for subject, start in operations_list %}
<div class="panel panel-default"> <div class="panel panel-default">
@@ -31,7 +31,7 @@
</tr> </tr>
<tr> <tr>
<td class="col-md-6">{{ start.start|date:"l d M H:i" }} <span class="label label-success">{% trans "Eve Time" %}</span></td> <td class="col-md-6">{{ start.start|date:"l d M H:i" }} <span class="label label-success">{% trans "Eve Time" %}</span></td>
<td class="col-md-6">{{ start.end|date:"l d M H:i" }} <span class="label label-success">{% trans "Eve Time" %}</span></td> <td class="col-md-6">{{ start.end|date:"l d M H:i" }} <span class="label label-success">{% trans "Eve Time" %}</span></td>
</tr> </tr>
<tr> <tr>
@@ -39,13 +39,12 @@
<span id="localtime{{ start.operation_id }}"></span>&nbsp;<span class='label label-success'>Local time</span><br> <span id="localtime{{ start.operation_id }}"></span>&nbsp;<span class='label label-success'>Local time</span><br>
<div id="countdown{{ start.operation_id }}"></div> <div id="countdown{{ start.operation_id }}"></div>
</td> </td>
<td class="col-md-6"></td> <td class="col-md-6"></td>
</tr> </tr>
</table> </table>
<p>{{ start.details }}</p> {{ start.details|linebreaks }}
<div class="col-lg-12">
<table class="table table-condensed table-striped"> <table class="table table-condensed table-striped">
<tr> <tr>
<th class="col-md-4">{% trans "Location" %}</th> <th class="col-md-4">{% trans "Location" %}</th>
@@ -60,11 +59,11 @@
<td> <td>
{% if start.doctrine %} {% if start.doctrine %}
{% for doctrine in start.doctrine %} {% for doctrine in start.doctrine %}
<a href="{% url 'fleetup:doctrine' doctrine.Id %}" class="label label-success">{{ doctrine.Name }}</a> <a href="{% url 'fleetup:doctrine' doctrine.Id %}" class="label label-success">{{ doctrine.Name }}</a>
{% endfor %} {% endfor %}
{% else %} {% else %}
<span class="label label-danger">{% trans "TBA" %}</span> <span class="label label-danger">{% trans "TBA" %}</span>
{% endif %} {% endif %}
@@ -81,7 +80,6 @@
</td> </td>
</tr> </tr>
</table> </table>
</div>
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
@@ -89,7 +87,7 @@
<h3>{% trans "There seems to be no Operations in the near future." %}</h3> <h3>{% trans "There seems to be no Operations in the near future." %}</h3>
{% endif %} {% endif %}
</div> </div>
<div class="col-lg-3"> <div class="col-lg-4">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h2 class="panel-title">{% trans "Current Eve Time:" %}</h2> <h2 class="panel-title">{% trans "Current Eve Time:" %}</h2>
@@ -158,7 +156,7 @@
<td> <td>
{{ type.owner }} {{ type.owner }}
</td> </td>
<td> <td>
{{ type.notes }} {{ type.notes }}
</td> </td>
</tr> </tr>

View File

@@ -8,8 +8,8 @@ from .models import GroupRequest
class AuthGroupInlineAdmin(admin.StackedInline): class AuthGroupInlineAdmin(admin.StackedInline):
model = AuthGroup model = AuthGroup
filter_horizontal = ('group_leaders',) filter_horizontal = ('group_leaders', 'states',)
fields = ('description', 'group_leaders', 'internal', 'hidden', 'open', 'public') fields = ('description', 'group_leaders', 'states', 'internal', 'hidden', 'open', 'public')
verbose_name_plural = 'Auth Settings' verbose_name_plural = 'Auth Settings'
verbose_name = '' verbose_name = ''

View File

@@ -1,4 +1,5 @@
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.db.models import Q
class GroupManager: class GroupManager:
@@ -6,7 +7,12 @@ class GroupManager:
pass pass
@staticmethod @staticmethod
def get_joinable_groups(): def get_joinable_groups(state):
return Group.objects.select_related('authgroup').exclude(authgroup__internal=True)\
.filter(Q(authgroup__states=state) | Q(authgroup__states=None))
@staticmethod
def get_all_non_internal_groups():
return Group.objects.select_related('authgroup').exclude(authgroup__internal=True) return Group.objects.select_related('authgroup').exclude(authgroup__internal=True)
@staticmethod @staticmethod
@@ -14,13 +20,35 @@ class GroupManager:
return Group.objects.select_related('authgroup').filter(authgroup__group_leaders__in=[user]) return Group.objects.select_related('authgroup').filter(authgroup__group_leaders__in=[user])
@staticmethod @staticmethod
def joinable_group(group): def joinable_group(group, state):
""" """
Check if a group is a user joinable group, i.e. Check if a group is a user/state joinable group, i.e.
not an internal group for Corp, Alliance, Members etc not an internal group for Corp, Alliance, Members etc,
or restricted from the user's current state.
:param group: django.contrib.auth.models.Group object :param group: django.contrib.auth.models.Group object
:param state: allianceauth.authentication.State object
:return: bool True if its joinable, False otherwise :return: bool True if its joinable, False otherwise
""" """
if len(group.authgroup.states.all()) != 0 and state not in group.authgroup.states.all():
return False
return not group.authgroup.internal
@staticmethod
def check_internal_group(group):
"""
Check if a group is auditable, i.e not an internal group
:param group: django.contrib.auth.models.Group object
:return: bool True if it is auditable, false otherwise
"""
return not group.authgroup.internal
@staticmethod
def check_internal_group(group):
"""
Check if a group is auditable, i.e not an internal group
:param group: django.contrib.auth.models.Group object
:return: bool True if it is auditable, false otherwise
"""
return not group.authgroup.internal return not group.authgroup.internal
@staticmethod @staticmethod

View File

@@ -0,0 +1,28 @@
# Generated by Django 2.0.6 on 2018-06-04 02:45
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('auth', '0008_alter_user_username_max_length'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('groupmanagement', '0008_remove_authgroup_permissions'),
]
operations = [
migrations.CreateModel(
name='RequestLog',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('request_type', models.NullBooleanField(default=0)),
('request_info', models.CharField(max_length=254)),
('action', models.BooleanField(default=0)),
('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.Group')),
('request_actor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 2.0.6 on 2018-07-11 00:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('authentication', '0016_ownershiprecord'),
('groupmanagement', '0009_requestlog'),
]
operations = [
migrations.AddField(
model_name='authgroup',
name='states',
field=models.ManyToManyField(blank=True, help_text='States listed here will have the ability to join this group provided they have the proper permissions.', related_name='valid_states', to='authentication.State'),
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 2.0.8 on 2018-12-07 08:56
import datetime
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('groupmanagement', '0010_authgroup_states'),
]
operations = [
migrations.AddField(
model_name='requestlog',
name='date',
field=models.DateTimeField(default=datetime.datetime(2018, 12, 7, 8, 56, 33, 846342)),
),
]

View File

@@ -3,6 +3,8 @@ from django.contrib.auth.models import User
from django.db import models from django.db import models
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django.dispatch import receiver from django.dispatch import receiver
from allianceauth.authentication.models import State
from datetime import datetime
class GroupRequest(models.Model): class GroupRequest(models.Model):
@@ -23,6 +25,38 @@ class GroupRequest(models.Model):
return self.user.username + ":" + self.group.name return self.user.username + ":" + self.group.name
class RequestLog(models.Model):
request_type = models.NullBooleanField(default=0)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
request_info = models.CharField(max_length=254)
action = models.BooleanField(default=0)
request_actor = models.ForeignKey(User, on_delete=models.CASCADE)
date = models.DateTimeField(auto_now_add=datetime.utcnow())
def requestor(self):
return self.request_info.split(":")[0]
def type_to_str(self):
if self.request_type is None:
return "Removed"
elif self.request_type is True:
return "Leave"
elif self.request_type is False:
return "Join"
def action_to_str(self):
if self.action is True:
return "Accept"
elif self.action is False:
return "Reject"
def req_char(self):
usr = self.requestor()
user = User.objects.get(username=usr)
return user.profile.main_character
class AuthGroup(models.Model): class AuthGroup(models.Model):
""" """
Extends Django Group model with a one-to-one field Extends Django Group model with a one-to-one field
@@ -65,6 +99,10 @@ class AuthGroup(models.Model):
"specifically. Use the auth.group_management permission to allow " "specifically. Use the auth.group_management permission to allow "
"a user to manage all groups.") "a user to manage all groups.")
states = models.ManyToManyField(State, related_name='valid_states', blank=True,
help_text="States listed here will have the ability to join this group provided "
"they have the proper permissions.")
description = models.CharField(max_length=512, blank=True, help_text="Description of the group shown to users.") description = models.CharField(max_length=512, blank=True, help_text="Description of the group shown to users.")
def __str__(self): def __str__(self):

View File

@@ -0,0 +1,62 @@
{% extends "allianceauth/base.html" %}
{% load staticfiles %}
{% load i18n %}
{% block page_title %}{{ group }} {% trans "Audit Log" %}{% endblock page_title %}
{% block content %}
<div class="col-lg-12">
<br>
{% include 'groupmanagement/menu.html' %}
<div>
<h3>{{ group }} Audit Log</h3>
<p> All times displayed are EVE/UTC.</p>
{% if entries %}
<div class="table-responsive">
<table class="table table-striped" id="log-entries">
<thead>
<th class="text-center" scope="col">{% trans "Date/Time" %}</th>
<th class="text-center" scope="col">{% trans "Requestor" %}</th>
<th class="text-center" scope="col">{% trans "Main Character" %}</th>
<th class="text-center" scope="col">{% trans "Group" %}</th>
<th class="text-center" scope="col">{% trans "Type" %}</th>
<th class="text-center" scope="col">{% trans "Action" %}</th>
<th class="text-center" scope="col">{% trans "Actor" %}</th>
</thead>
<tbody>
{% for entry in entries %}
<tr>
<td class="text-center">{{ entry.date }}</td>
<td class="text-center">{{ entry.requestor }}</td>
<td class="text-center">{{ entry.req_char }}</td>
<td class="text-center">{{ entry.group }}</td>
<td class="text-center">{{ entry.type_to_str }}</td>
{% if entry.request_type is None %}
<td class="text-center"> Removed</td>
{% else %}
<td class="text-center">{{ entry.action_to_str }}</td>
{% endif %}
<td class="text-center">{{ entry.request_actor }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="alert alert-warning text-center">{% trans "No entries found for this group." %}</div>
{% endif %}
</div>
</div>
{% endblock %}
{% block extra_javascript %}
{% include 'bundles/datatables-js.html' %}
{% endblock %}
{% block extra_css %}
{% include 'bundles/datatables-css.html' %}
{% endblock %}
{% block extra_script %}
$(document).ready(function(){
$('#log-entries').DataTable();
});
{% endblock %}

View File

@@ -41,6 +41,9 @@
title="{% trans "View Members" %}"> title="{% trans "View Members" %}">
<i class="glyphicon glyphicon-eye-open"></i> <i class="glyphicon glyphicon-eye-open"></i>
</a> </a>
<a href="{% url "groupmanagement:audit_log" group.id %}" class="btn btn-info" title="{% trans "Audit Members" %}">
<i class="glyphicon glyphicon-list-alt"></i>
</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@@ -12,6 +12,7 @@ urlpatterns = [
name='membership'), name='membership'),
url(r'^membership/(\w+)/$', views.group_membership_list, url(r'^membership/(\w+)/$', views.group_membership_list,
name='membership_list'), name='membership_list'),
url(r'^membership/(\w+)/audit/$', views.group_membership_audit, name="audit_log"),
url(r'^membership/(\w+)/remove/(\w+)/$', views.group_membership_remove, url(r'^membership/(\w+)/remove/(\w+)/$', views.group_membership_remove,
name='membership_remove'), name='membership_remove'),
url(r'^request_add/(\w+)', views.group_request_add, url(r'^request_add/(\w+)', views.group_request_add,

View File

@@ -5,15 +5,18 @@ from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import user_passes_test from django.contrib.auth.decorators import user_passes_test
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.core.paginator import Paginator, EmptyPage
from django.db.models import Count from django.db.models import Count
from django.http import Http404 from django.http import Http404
from django.shortcuts import render, redirect, get_object_or_404 from django.shortcuts import render, redirect, get_object_or_404
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from .managers import GroupManager from .managers import GroupManager
from .models import GroupRequest from .models import GroupRequest, RequestLog
from allianceauth.notifications import notify from allianceauth.notifications import notify
from django.conf import settings
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -53,7 +56,7 @@ def group_membership(request):
# Get all open and closed groups # Get all open and closed groups
if GroupManager.has_management_permission(request.user): if GroupManager.has_management_permission(request.user):
# Full access # Full access
groups = GroupManager.get_joinable_groups() groups = GroupManager.get_all_non_internal_groups()
else: else:
# Group leader specific # Group leader specific
groups = GroupManager.get_group_leaders_groups(request.user) groups = GroupManager.get_group_leaders_groups(request.user)
@@ -65,6 +68,31 @@ def group_membership(request):
return render(request, 'groupmanagement/groupmembership.html', context=render_items) return render(request, 'groupmanagement/groupmembership.html', context=render_items)
@login_required
@user_passes_test(GroupManager.can_manage_groups)
def group_membership_audit(request, group_id):
logger.debug("group_management_audit called by user %s" % request.user)
group = get_object_or_404(Group, id=group_id)
try:
# Check its a joinable group i.e. not corp or internal
# And the user has permission to manage it
if not GroupManager.check_internal_group(group) or not GroupManager.can_manage_group(request.user, group):
logger.warning("User %s attempted to view the membership of group %s but permission was denied" %
(request.user, group_id))
raise PermissionDenied
except ObjectDoesNotExist:
raise Http404("Group does not exist")
render_items = {'group': group.name}
entries = RequestLog.objects.filter(group=group).order_by('-date')
render_items['entries'] = entries
return render(request, 'groupmanagement/audit.html', context=render_items)
@login_required @login_required
@user_passes_test(GroupManager.can_manage_groups) @user_passes_test(GroupManager.can_manage_groups)
def group_membership_list(request, group_id): def group_membership_list(request, group_id):
@@ -74,7 +102,7 @@ def group_membership_list(request, group_id):
# Check its a joinable group i.e. not corp or internal # Check its a joinable group i.e. not corp or internal
# And the user has permission to manage it # And the user has permission to manage it
if not GroupManager.joinable_group(group) or not GroupManager.can_manage_group(request.user, group): if not GroupManager.check_internal_group(group) or not GroupManager.can_manage_group(request.user, group):
logger.warning("User %s attempted to view the membership of group %s but permission was denied" % logger.warning("User %s attempted to view the membership of group %s but permission was denied" %
(request.user, group_id)) (request.user, group_id))
raise PermissionDenied raise PermissionDenied
@@ -105,13 +133,16 @@ def group_membership_remove(request, group_id, user_id):
try: try:
# Check its a joinable group i.e. not corp or internal # Check its a joinable group i.e. not corp or internal
# And the user has permission to manage it # And the user has permission to manage it
if not GroupManager.joinable_group(group) or not GroupManager.can_manage_group(request.user, group): if not GroupManager.check_internal_group(group) or not GroupManager.can_manage_group(request.user, group):
logger.warning("User %s attempted to remove a user from group %s but permission was denied" % (request.user, logger.warning("User %s attempted to remove a user from group %s but permission was denied" % (request.user,
group_id)) group_id))
raise PermissionDenied raise PermissionDenied
try: try:
user = group.user_set.get(id=user_id) user = group.user_set.get(id=user_id)
request_info = user.username + ":" + group.name
log = RequestLog(request_type=None,group=group,request_info=request_info,action=1,request_actor=request.user)
log.save()
# Remove group from user # Remove group from user
user.groups.remove(group) user.groups.remove(group)
logger.info("User %s removed user %s from group %s" % (request.user, user, group)) logger.info("User %s removed user %s from group %s" % (request.user, user, group))
@@ -133,12 +164,14 @@ def group_accept_request(request, group_request_id):
try: try:
group, created = Group.objects.get_or_create(name=group_request.group.name) group, created = Group.objects.get_or_create(name=group_request.group.name)
if not GroupManager.joinable_group(group_request.group) or \ if not GroupManager.joinable_group(group_request.group, group_request.user.profile.state) or \
not GroupManager.can_manage_group(request.user, group_request.group): not GroupManager.can_manage_group(request.user, group_request.group):
raise PermissionDenied raise PermissionDenied
group_request.user.groups.add(group) group_request.user.groups.add(group)
group_request.user.save() group_request.user.save()
log = RequestLog(request_type=group_request.leave_request,group=group,request_info=group_request.__str__(),action=1,request_actor=request.user)
log.save()
group_request.delete() group_request.delete()
logger.info("User %s accepted group request from user %s to group %s" % ( logger.info("User %s accepted group request from user %s to group %s" % (
request.user, group_request.user, group_request.group.name)) request.user, group_request.user, group_request.group.name))
@@ -172,6 +205,8 @@ def group_reject_request(request, group_request_id):
if group_request: if group_request:
logger.info("User %s rejected group request from user %s to group %s" % ( logger.info("User %s rejected group request from user %s to group %s" % (
request.user, group_request.user, group_request.group.name)) request.user, group_request.user, group_request.group.name))
log = RequestLog(request_type=group_request.leave_request,group=group_request.group,request_info=group_request.__str__(),action=0,request_actor=request.user)
log.save()
group_request.delete() group_request.delete()
notify(group_request.user, "Group Application Rejected", level="danger", notify(group_request.user, "Group Application Rejected", level="danger",
message="Your application to %s has been rejected." % group_request.group) message="Your application to %s has been rejected." % group_request.group)
@@ -204,6 +239,8 @@ def group_leave_accept_request(request, group_request_id):
group, created = Group.objects.get_or_create(name=group_request.group.name) group, created = Group.objects.get_or_create(name=group_request.group.name)
group_request.user.groups.remove(group) group_request.user.groups.remove(group)
group_request.user.save() group_request.user.save()
log = RequestLog(request_type=group_request.leave_request,group=group_request.group,request_info=group_request.__str__(),action=1,request_actor=request.user)
log.save()
group_request.delete() group_request.delete()
logger.info("User %s accepted group leave request from user %s to group %s" % ( logger.info("User %s accepted group leave request from user %s to group %s" % (
request.user, group_request.user, group_request.group.name)) request.user, group_request.user, group_request.group.name))
@@ -236,6 +273,8 @@ def group_leave_reject_request(request, group_request_id):
raise PermissionDenied raise PermissionDenied
if group_request: if group_request:
log = RequestLog(request_type=group_request.leave_request,group=group_request.group,request_info=group_request.__str__(),action=0,request_actor=request.user)
log.save()
group_request.delete() group_request.delete()
logger.info("User %s rejected group leave request from user %s for group %s" % ( logger.info("User %s rejected group leave request from user %s for group %s" % (
request.user, group_request.user, group_request.group.name)) request.user, group_request.user, group_request.group.name))
@@ -262,7 +301,7 @@ def groups_view(request):
logger.debug("groups_view called by user %s" % request.user) logger.debug("groups_view called by user %s" % request.user)
groups = [] groups = []
group_query = GroupManager.get_joinable_groups() group_query = GroupManager.get_joinable_groups(request.user.profile.state)
if not request.user.has_perm('groupmanagement.request_groups'): if not request.user.has_perm('groupmanagement.request_groups'):
# Filter down to public groups only for non-members # Filter down to public groups only for non-members
@@ -284,11 +323,18 @@ def groups_view(request):
def group_request_add(request, group_id): def group_request_add(request, group_id):
logger.debug("group_request_add called by user %s for group id %s" % (request.user, group_id)) logger.debug("group_request_add called by user %s for group id %s" % (request.user, group_id))
group = Group.objects.get(id=group_id) group = Group.objects.get(id=group_id)
if not GroupManager.joinable_group(group): state = request.user.profile.state
if not GroupManager.joinable_group(group, state):
logger.warning("User %s attempted to join group id %s but it is not a joinable group" % logger.warning("User %s attempted to join group id %s but it is not a joinable group" %
(request.user, group_id)) (request.user, group_id))
messages.warning(request, _("You cannot join that group")) messages.warning(request, _("You cannot join that group"))
return redirect('groupmanagement:groups') return redirect('groupmanagement:groups')
if group in request.user.groups.all():
# User is already a member of this group.
logger.warning("User %s attempted to join group id %s but they are already a member." %
(request.user, group_id))
messages.warning(request, "You are already a member of that group.")
return redirect('groupmanagement:groups')
if not request.user.has_perm('groupmanagement.request_groups') and not group.authgroup.public: if not request.user.has_perm('groupmanagement.request_groups') and not group.authgroup.public:
# Does not have the required permission, trying to join a non-public group # Does not have the required permission, trying to join a non-public group
logger.warning("User %s attempted to join group id %s but it is not a public group" % logger.warning("User %s attempted to join group id %s but it is not a public group" %
@@ -299,6 +345,11 @@ def group_request_add(request, group_id):
logger.info("%s joining %s as is an open group" % (request.user, group)) logger.info("%s joining %s as is an open group" % (request.user, group))
request.user.groups.add(group) request.user.groups.add(group)
return redirect("groupmanagement:groups") return redirect("groupmanagement:groups")
req = GroupRequest.objects.filter(user=request.user, group=group)
if len(req) > 0:
logger.info("%s attempted to join %s but already has an open application" % (request.user, group))
messages.warning(request, "You already have a pending application for that group.")
return redirect("groupmanagement:groups")
grouprequest = GroupRequest() grouprequest = GroupRequest()
grouprequest.status = _('Pending') grouprequest.status = _('Pending')
grouprequest.group = group grouprequest.group = group
@@ -314,7 +365,7 @@ def group_request_add(request, group_id):
def group_request_leave(request, group_id): def group_request_leave(request, group_id):
logger.debug("group_request_leave called by user %s for group id %s" % (request.user, group_id)) logger.debug("group_request_leave called by user %s for group id %s" % (request.user, group_id))
group = Group.objects.get(id=group_id) group = Group.objects.get(id=group_id)
if not GroupManager.joinable_group(group): if not GroupManager.check_internal_group(group):
logger.warning("User %s attempted to leave group id %s but it is not a joinable group" % logger.warning("User %s attempted to leave group id %s but it is not a joinable group" %
(request.user, group_id)) (request.user, group_id))
messages.warning(request, _("You cannot leave that group")) messages.warning(request, _("You cannot leave that group"))
@@ -328,6 +379,15 @@ def group_request_leave(request, group_id):
logger.info("%s leaving %s as is an open group" % (request.user, group)) logger.info("%s leaving %s as is an open group" % (request.user, group))
request.user.groups.remove(group) request.user.groups.remove(group)
return redirect("groupmanagement:groups") return redirect("groupmanagement:groups")
req = GroupRequest.objects.filter(user=request.user, group=group)
if len(req) > 0:
logger.info("%s attempted to leave %s but already has an pending leave request." % (request.user, group))
messages.warning(request, "You already have a pending leave request for that group.")
return redirect("groupmanagement:groups")
if getattr(settings, 'AUTO_LEAVE', False):
logger.info("%s leaving joinable group %s due to auto_leave" % (request.user, group))
request.user.groups.remove(group)
return redirect('groupmanagement:groups')
grouprequest = GroupRequest() grouprequest = GroupRequest()
grouprequest.status = _('Pending') grouprequest.status = _('Pending')
grouprequest.group = group grouprequest.group = group

View File

@@ -1,5 +1,5 @@
from allianceauth.services.hooks import MenuItemHook, UrlHook from allianceauth.services.hooks import MenuItemHook, UrlHook
from django.utils.translation import ugettext_lazy as _
from allianceauth import hooks from allianceauth import hooks
from allianceauth.hrapplications import urls from allianceauth.hrapplications import urls
@@ -7,7 +7,7 @@ from allianceauth.hrapplications import urls
class ApplicationsMenu(MenuItemHook): class ApplicationsMenu(MenuItemHook):
def __init__(self): def __init__(self):
MenuItemHook.__init__(self, MenuItemHook.__init__(self,
'Applications', _('Applications'),
'fa fa-file-o fa-fw', 'fa fa-file-o fa-fw',
'hrapplications:index', 'hrapplications:index',
navactive=['hrapplications:']) navactive=['hrapplications:'])

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,12 @@
from allianceauth.services.hooks import MenuItemHook, UrlHook from allianceauth.services.hooks import MenuItemHook, UrlHook
from django.utils.translation import ugettext_lazy as _
from allianceauth import hooks from allianceauth import hooks
from . import urls from . import urls
class OpTimerboardMenu(MenuItemHook): class OpTimerboardMenu(MenuItemHook):
def __init__(self): def __init__(self):
MenuItemHook.__init__(self, 'Fleet Operations', MenuItemHook.__init__(self, _('Fleet Operations'),
'fa fa-exclamation fa-fw', 'fa fa-exclamation fa-fw',
'optimer:view', 'optimer:view',
navactive=['optimer:']) navactive=['optimer:'])

View File

@@ -19,7 +19,8 @@
<div class="col-lg-12 text-center row"> <div class="col-lg-12 text-center row">
<div class="label label-info text-left"> <div class="label label-info text-left">
<b>{% trans "Current Eve Time:" %} </b> <b>{% trans "Current Eve Time:" %} </b>
</div><div class="label label-info text-left" id="current-time"></div> </div>
<strong class="label label-info text-left" id="current-time"></strong>
<br /> <br />
</div> </div>
@@ -111,7 +112,7 @@
} }
function updateClock() { function updateClock() {
document.getElementById("current-time").innerHTML = "<b>" + moment.utc().format('LLLL') + "</b>"; document.getElementById("current-time").innerHTML = getCurrentEveTimeString();
} }
</script> </script>
{% endblock content %} {% endblock content %}

View File

@@ -82,6 +82,7 @@ ugettext = lambda s: s
LANGUAGES = ( LANGUAGES = (
('en', ugettext('English')), ('en', ugettext('English')),
('de', ugettext('German')), ('de', ugettext('German')),
('es', ugettext('Spanish')),
) )
TEMPLATES = [ TEMPLATES = [
@@ -193,6 +194,8 @@ LOGIN_TOKEN_SCOPES = ['publicData']
# number of days email verification links are valid for # number of days email verification links are valid for
ACCOUNT_ACTIVATION_DAYS = 1 ACCOUNT_ACTIVATION_DAYS = 1
ESI_API_URL = 'https://esi.evetech.net/'
LOGGING = { LOGGING = {
'version': 1, 'version': 1,
'disable_existing_loggers': False, 'disable_existing_loggers': False,

View File

@@ -219,22 +219,18 @@ class DiscordOAuthManager:
@staticmethod @staticmethod
@api_backoff @api_backoff
def update_nickname(user_id, nickname): def update_nickname(user_id, nickname):
try: nickname = DiscordOAuthManager._sanitize_name(nickname)
nickname = DiscordOAuthManager._sanitize_name(nickname) custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN} data = {'nick': nickname}
data = {'nick': nickname} path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id)
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id) r = requests.patch(path, headers=custom_headers, json=data)
r = requests.patch(path, headers=custom_headers, json=data) logger.debug("Got status code %s after setting nickname for Discord user ID %s (%s)" % (
logger.debug("Got status code %s after setting nickname for Discord user ID %s (%s)" % ( r.status_code, user_id, nickname))
r.status_code, user_id, nickname)) if r.status_code == 404:
if r.status_code == 404: logger.warn("Discord user ID %s could not be found in server." % user_id)
logger.warn("Discord user ID %s could not be found in server." % user_id)
return True
r.raise_for_status()
return True return True
except: r.raise_for_status()
logger.exception("Failed to set nickname for Discord user ID %s (%s)" % (user_id, nickname)) return True
return False
@staticmethod @staticmethod
def delete_user(user_id): def delete_user(user_id):

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='discorduser', name='discorduser',
options={'permissions': (('access_discord', 'Can access the Discord service'),)}, options={'permissions': (('access_discord', 'Can access the Discord service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -235,7 +235,7 @@ class DiscourseManager:
@staticmethod @staticmethod
def __add_user_to_group(g_id, username): def __add_user_to_group(g_id, username):
endpoint = ENDPOINTS['groups']['add_user'] endpoint = ENDPOINTS['groups']['add_user']
DiscourseManager.__exc(endpoint, g_id, usernames=[username]) DiscourseManager.__exc(endpoint, g_id, usernames=username)
@staticmethod @staticmethod
def __remove_user_from_group(g_id, username): def __remove_user_from_group(g_id, username):
@@ -355,11 +355,14 @@ class DiscourseManager:
user_groups = DiscourseManager.__get_user_groups(username) user_groups = DiscourseManager.__get_user_groups(username)
add_groups = [group_dict[x] for x in group_dict if not group_dict[x] in user_groups] add_groups = [group_dict[x] for x in group_dict if not group_dict[x] in user_groups]
rem_groups = [x for x in user_groups if x not in inv_group_dict] rem_groups = [x for x in user_groups if x not in inv_group_dict]
if add_groups or rem_groups: if add_groups:
logger.info( logger.info(
"Updating discourse user %s groups: adding %s, removing %s" % (username, add_groups, rem_groups)) "Updating discourse user %s groups: adding %s" % (username, add_groups))
for g in add_groups: for g in add_groups:
DiscourseManager.__add_user_to_group(g, username) DiscourseManager.__add_user_to_group(g, username)
if rem_groups:
logger.info(
"Updating discourse user %s groups: removing %s" % (username, rem_groups))
for g in rem_groups: for g in rem_groups:
DiscourseManager.__remove_user_from_group(g, username) DiscourseManager.__remove_user_from_group(g, username)

View File

@@ -58,5 +58,5 @@ class Migration(migrations.Migration):
name='discourseuser', name='discourseuser',
options={'permissions': (('access_discourse', 'Can access the Discourse service'),)}, options={'permissions': (('access_discourse', 'Can access the Discourse service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -1,8 +1,10 @@
{% load i18n %} {% load i18n %}
<td class="text-center">Discourse</td> <tr>
<td class="text-center">{{ char.character_name }}</td> <td class="text-center">Discourse</td>
<td class="text-center"><a href="{{ DISCOURSE_URL }}">{{ DISCOURSE_URL }}</a></td> <td class="text-center">{{ char.character_name }}</td>
<td class="text-center"> <td class="text-center"><a href="{{ DISCOURSE_URL }}">{{ DISCOURSE_URL }}</a></td>
<a title="Go To Forums" class="btn btn-success" href="{{ DISCOURSE_URL }}"><span class="glyphicon glyphicon-arrow-right"></span></a> <td class="text-center">
</td> <a title="Go To Forums" class="btn btn-success" href="{{ DISCOURSE_URL }}"><span class="glyphicon glyphicon-arrow-right"></span></a>
</td>
</tr>

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='ips4user', name='ips4user',
options={'permissions': (('access_ips4', 'Can access the IPS4 service'),)}, options={'permissions': (('access_ips4', 'Can access the IPS4 service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='marketuser', name='marketuser',
options={'permissions': (('access_market', 'Can access the Evernus Market service'),)}, options={'permissions': (('access_market', 'Can access the Evernus Market service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -1,4 +1,5 @@
import logging import logging
import urllib
from django.conf import settings from django.conf import settings
from django.template.loader import render_to_string from django.template.loader import render_to_string
@@ -61,7 +62,7 @@ class MumbleService(ServicesHook):
'service_name': self.title, 'service_name': self.title,
'urls': urls, 'urls': urls,
'service_url': self.service_url, 'service_url': self.service_url,
'connect_url': request.user.mumble.username + '@' + self.service_url if MumbleTasks.has_account(request.user) else self.service_url, 'connect_url': urllib.parse.quote(request.user.mumble.username, safe="") + '@' + self.service_url if MumbleTasks.has_account(request.user) else self.service_url,
'username': request.user.mumble.username if MumbleTasks.has_account(request.user) else '', 'username': request.user.mumble.username if MumbleTasks.has_account(request.user) else '',
}, request=request) }, request=request)

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='mumbleuser', name='mumbleuser',
options={'permissions': (('access_mumble', 'Can access the Mumble service'),)}, options={'permissions': (('access_mumble', 'Can access the Mumble service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='openfireuser', name='openfireuser',
options={'permissions': (('access_openfire', 'Can access the Openfire service'),)}, options={'permissions': (('access_openfire', 'Can access the Openfire service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='phpbb3user', name='phpbb3user',
options={'permissions': (('access_phpbb3', 'Can access the phpBB3 service'),)}, options={'permissions': (('access_phpbb3', 'Can access the phpBB3 service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='smfuser', name='smfuser',
options={'permissions': (('access_smf', 'Can access the SMF service'),)}, options={'permissions': (('access_smf', 'Can access the SMF service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -67,6 +67,8 @@ class Teamspeak3Manager:
group_cache = self.server.send_command('servergrouplist') group_cache = self.server.send_command('servergrouplist')
logger.debug("Received group cache from server: %s" % group_cache) logger.debug("Received group cache from server: %s" % group_cache)
for group in group_cache: for group in group_cache:
if group['keys']['type'] != '1':
continue
logger.debug("Checking group %s" % group) logger.debug("Checking group %s" % group)
if group['keys']['name'] == groupname: if group['keys']['name'] == groupname:
logger.debug("Found group %s, returning id %s" % (groupname, group['keys']['sgid'])) logger.debug("Found group %s, returning id %s" % (groupname, group['keys']['sgid']))
@@ -124,6 +126,8 @@ class Teamspeak3Manager:
outlist = {} outlist = {}
if group_cache: if group_cache:
for group in group_cache: for group in group_cache:
if group['keys']['type'] != '1':
continue
logger.debug("Assigning name/id dict: %s = %s" % (group['keys']['name'], group['keys']['sgid'])) logger.debug("Assigning name/id dict: %s = %s" % (group['keys']['name'], group['keys']['sgid']))
outlist[group['keys']['name']] = group['keys']['sgid'] outlist[group['keys']['name']] = group['keys']['sgid']
else: else:
@@ -179,18 +183,19 @@ class Teamspeak3Manager:
except: except:
logger.exception("An unhandled exception has occured while syncing TS groups.") logger.exception("An unhandled exception has occured while syncing TS groups.")
def add_user(self, username): def add_user(self, user, fmt_name):
username_clean = self.__santatize_username(username[:30]) username_clean = self.__santatize_username(fmt_name[:30])
logger.debug("Adding user to TS3 server with cleaned username %s" % username_clean) logger.debug("Adding user to TS3 server with cleaned username %s" % username_clean)
server_groups = self._group_list() server_groups = self._group_list()
if 'Member' not in server_groups: state = user.profile.state.name
self._create_group('Member') if state not in server_groups:
self._create_group(state)
alliance_group_id = self._group_id_by_name('Member') state_group_id = self._group_id_by_name(state)
try: try:
ret = self.server.send_command('tokenadd', {'tokentype': 0, 'tokenid1': alliance_group_id, 'tokenid2': 0, ret = self.server.send_command('tokenadd', {'tokentype': 0, 'tokenid1': state_group_id, 'tokenid2': 0,
'tokendescription': username_clean, 'tokendescription': username_clean,
'tokencustomset': "ident=sso_uid value=%s" % username_clean}) 'tokencustomset': "ident=sso_uid value=%s" % username_clean})
except TeamspeakError as e: except TeamspeakError as e:
@@ -213,7 +218,7 @@ class Teamspeak3Manager:
if isinstance(clients, dict): if isinstance(clients, dict):
# Rewrap list # Rewrap list
clients = [clients] clients = [clients]
for client in clients: for client in clients:
try: try:
if client['keys']['client_database_id'] == user: if client['keys']['client_database_id'] == user:
@@ -244,10 +249,10 @@ class Teamspeak3Manager:
return False return False
def generate_new_permissionkey(self, uid, username): def generate_new_permissionkey(self, uid, user, username):
logger.debug("Re-issuing permission key for user id %s" % uid) logger.debug("Re-issuing permission key for user id %s" % uid)
self.delete_user(uid) self.delete_user(uid)
return self.add_user(username) return self.add_user(user, username)
def update_groups(self, uid, ts_groups): def update_groups(self, uid, ts_groups):
logger.debug("Updating uid %s TS3 groups %s" % (uid, ts_groups)) logger.debug("Updating uid %s TS3 groups %s" % (uid, ts_groups))

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='teamspeak3user', name='teamspeak3user',
options={'permissions': (('access_teamspeak3', 'Can access the Teamspeak3 service'),)}, options={'permissions': (('access_teamspeak3', 'Can access the Teamspeak3 service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -22,7 +22,7 @@ def activate_teamspeak3(request):
character = request.user.profile.main_character character = request.user.profile.main_character
with Teamspeak3Manager() as ts3man: with Teamspeak3Manager() as ts3man:
logger.debug("Adding TS3 user for user %s with main character %s" % (request.user, character)) logger.debug("Adding TS3 user for user %s with main character %s" % (request.user, character))
result = ts3man.add_user(Teamspeak3Tasks.get_username(request.user)) result = ts3man.add_user(request.user, Teamspeak3Tasks.get_username(request.user))
# if its empty we failed # if its empty we failed
if result[0] is not "": if result[0] is not "":
@@ -79,13 +79,12 @@ def reset_teamspeak3_perm(request):
logger.debug("reset_teamspeak3_perm called by user %s" % request.user) logger.debug("reset_teamspeak3_perm called by user %s" % request.user)
if not Teamspeak3Tasks.has_account(request.user): if not Teamspeak3Tasks.has_account(request.user):
return redirect("services:services") return redirect("services:services")
character = request.user.profile.main_character
logger.debug("Deleting TS3 user for user %s" % request.user) logger.debug("Deleting TS3 user for user %s" % request.user)
with Teamspeak3Manager() as ts3man: with Teamspeak3Manager() as ts3man:
ts3man.delete_user(request.user.teamspeak3.uid) ts3man.delete_user(request.user.teamspeak3.uid)
logger.debug("Generating new permission key for user %s with main character %s" % (request.user, character)) logger.debug("Generating new permission key for user %s" % request.user)
result = ts3man.generate_new_permissionkey(request.user.teamspeak3.uid, character.character_name) result = ts3man.generate_new_permissionkey(request.user.teamspeak3.uid, request.user, Teamspeak3Tasks.get_username(request.user))
# if blank we failed # if blank we failed
if result[0] != "": if result[0] != "":

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='xenforouser', name='xenforouser',
options={'permissions': (('access_xenforo', 'Can access the XenForo service'),)}, options={'permissions': (('access_xenforo', 'Can access the XenForo service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -4,8 +4,8 @@ from celery import shared_task
from django.contrib.auth.models import User from django.contrib.auth.models import User
from .hooks import ServicesHook from .hooks import ServicesHook
from celery_once import QueueOnce as BaseTask, AlreadyQueued from celery_once import QueueOnce as BaseTask, AlreadyQueued
from celery_once.helpers import now_unix
from django.core.cache import cache from django.core.cache import cache
from time import time
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -22,7 +22,7 @@ class DjangoBackend:
@staticmethod @staticmethod
def raise_or_lock(key, timeout): def raise_or_lock(key, timeout):
now = now_unix() now = int(time())
result = cache.get(key) result = cache.get(key)
if result: if result:
remaining = int(result) - now remaining = int(result) - now

View File

@@ -1,12 +1,12 @@
from allianceauth.services.hooks import MenuItemHook, UrlHook from allianceauth.services.hooks import MenuItemHook, UrlHook
from django.utils.translation import ugettext_lazy as _
from allianceauth import hooks from allianceauth import hooks
from . import urls from . import urls
class SrpMenu(MenuItemHook): class SrpMenu(MenuItemHook):
def __init__(self): def __init__(self):
MenuItemHook.__init__(self, 'Ship Replacement', MenuItemHook.__init__(self, _('Ship Replacement'),
'fa fa-money fa-fw', 'fa fa-money fa-fw',
'srp:management', 'srp:management',
navactive=['srp:']) navactive=['srp:'])

View File

@@ -1,9 +1,15 @@
from allianceauth import NAME from allianceauth import NAME
from esi.clients import esi_client_factory
import requests import requests
import logging import logging
import os
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json')
"""
Swagger Operations:
get_killmails_killmail_id_killmail_hash
"""
class SRPManager: class SRPManager:
@@ -18,7 +24,7 @@ class SRPManager:
@staticmethod @staticmethod
def get_kill_data(kill_id): def get_kill_data(kill_id):
url = ("https://www.zkillboard.com/api/killID/%s/" % kill_id) url = ("https://zkillboard.com/api/killID/%s/" % kill_id)
headers = { headers = {
'User-Agent': NAME, 'User-Agent': NAME,
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -26,12 +32,20 @@ class SRPManager:
r = requests.get(url, headers=headers) r = requests.get(url, headers=headers)
result = r.json()[0] result = r.json()[0]
if result: if result:
ship_type = result['victim']['ship_type_id'] killmail_id = result['killmail_id']
killmail_hash = result['zkb']['hash']
c = esi_client_factory(spec_file=SWAGGER_SPEC_PATH)
km = c.Killmails.get_killmails_killmail_id_killmail_hash(killmail_id=killmail_id,
killmail_hash=killmail_hash).result()
else:
raise ValueError("Invalid Kill ID")
if km:
ship_type = km['victim']['ship_type_id']
logger.debug("Ship type for kill ID %s is %s" % (kill_id, ship_type)) logger.debug("Ship type for kill ID %s is %s" % (kill_id, ship_type))
ship_value = result['zkb']['totalValue'] ship_value = result['zkb']['totalValue']
logger.debug("Total loss value for kill id %s is %s" % (kill_id, ship_value)) logger.debug("Total loss value for kill id %s is %s" % (kill_id, ship_value))
victim_id = result['victim']['character_id'] victim_id = km['victim']['character_id']
return ship_type, ship_value, victim_id return ship_type, ship_value, victim_id
else: else:
raise ValueError("Invalid Kill ID") raise ValueError("Invalid Kill ID or Hash.")

File diff suppressed because one or more lines are too long

View File

@@ -17,6 +17,8 @@
<a href="{% url 'srp:all' %}" class="btn btn-primary"> <a href="{% url 'srp:all' %}" class="btn btn-primary">
{% trans "View All" %} {% trans "View All" %}
</a> </a>
{% endif %}
{% if perms.srp.add_srpfleetmain or perms.auth.srp_management %}
<a href="{% url 'srp:add' %}" class="btn btn-success"> <a href="{% url 'srp:add' %}" class="btn btn-success">
{% trans "Add SRP Fleet" %} {% trans "Add SRP Fleet" %}
</a> </a>

View File

@@ -10,6 +10,7 @@ from django.shortcuts import render, redirect, get_object_or_404
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.db.models import Sum from django.db.models import Sum
from allianceauth.authentication.decorators import permissions_required
from allianceauth.eveonline.providers import provider from allianceauth.eveonline.providers import provider
from allianceauth.notifications import notify from allianceauth.notifications import notify
from .form import SrpFleetMainForm from .form import SrpFleetMainForm
@@ -59,7 +60,7 @@ def srp_fleet_view(request, fleet_id):
@login_required @login_required
@permission_required('auth.srp_management') @permissions_required(('auth.srp_management', 'srp.add_srpfleetmain'))
def srp_fleet_add_view(request): def srp_fleet_add_view(request):
logger.debug("srp_fleet_add_view called by user %s" % request.user) logger.debug("srp_fleet_add_view called by user %s" % request.user)
completed = False completed = False

View File

@@ -8,8 +8,16 @@ function getDurationString(duration) {
if (duration.years()) { if (duration.years()) {
out += duration.years() + 'y '; out += duration.years() + 'y ';
} }
if (duration.months()) {
out += duration.months() + 'm ';
}
if (duration.days()) { if (duration.days()) {
out += duration.days() + 'd '; out += duration.days() + 'd ';
} }
return out + duration.hours() + "h " + duration.minutes() + "m " + duration.seconds() + "s"; return out + duration.hours() + "h " + duration.minutes() + "m " + duration.seconds() + "s";
} }
function getCurrentEveTimeString() {
return moment().utc().format('dddd LL HH:mm:ss')
}

View File

@@ -8,19 +8,19 @@
<ul class="list-group"> <ul class="list-group">
{% for notif in notifications %} {% for notif in notifications %}
<li class="list-group-item"> <li class="list-group-item">
{% if notif.state == 'open' %} {% if notif.state == 'opened' %}
<span class="label label-success">{% trans "Open" %}</span> <span class="label label-success">{% trans "Open" %}</span>
{% else %} {% else %}
<span class="label label-danger">{% trans "Closed" %}</span> <span class="label label-danger">{% trans "Closed" %}</span>
{% endif %} {% endif %}
<a href="{{ notif.html_url }}" target="_blank">#{{ notif.number }} {{ notif.title }}</a> <a href="{{ notif.web_url }}" target="_blank">#{{ notif.iid }} {{ notif.title }}</a>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
<div class="text-right" style="position:absolute;bottom:5px;right:5px;"> <div class="text-right" style="position:absolute;bottom:5px;right:5px;">
<a href="https://github.com/allianceauth/allianceauth/issues"><span class="label label-default"> <a href="https://gitlab.com/allianceauth/allianceauth/issues"><span class="label" style="background-color:#e65328;">
<i class="fa fa-github" aria-hidden="true"></i> Powered by Github</span> <i class="fa fa-gitlab" aria-hidden="true"></i> Powered by GitLab</span>
</a> </a>
</div> </div>
</div> </div>
@@ -39,7 +39,7 @@
<li class="list-group-item list-group-item-{% if latest_major %}success{% else %}warning{% endif %}"> <li class="list-group-item list-group-item-{% if latest_major %}success{% else %}warning{% endif %}">
<h4 class="list-group-item-heading">{% trans "Latest Major" %}</h4> <h4 class="list-group-item-heading">{% trans "Latest Major" %}</h4>
<p class="list-group-item-text"> <p class="list-group-item-text">
<a href="{{ latest_major_url }}" style="color:#000"><i class="fa fa-github" aria-hidden="true"></i> <a href="https://gitlab.com/allianceauth/allianceauth/tags" style="color:#000"><i class="fa fa-gitlab" aria-hidden="true"></i>
{{ latest_major_version }} {{ latest_major_version }}
</a> </a>
{% if not latest_major %}<br>{% trans "Update available" %}{% endif %} {% if not latest_major %}<br>{% trans "Update available" %}{% endif %}
@@ -48,7 +48,7 @@
<li class="list-group-item list-group-item-{% if latest_minor %}success{% else %}warning{% endif %}"> <li class="list-group-item list-group-item-{% if latest_minor %}success{% else %}warning{% endif %}">
<h4 class="list-group-item-heading">{% trans "Latest Minor" %}</h4> <h4 class="list-group-item-heading">{% trans "Latest Minor" %}</h4>
<p class="list-group-item-text"> <p class="list-group-item-text">
<a href="{{ latest_minor_url }}" style="color:#000"><i class="fa fa-github" aria-hidden="true"></i> <a href="https://gitlab.com/allianceauth/allianceauth/tags" style="color:#000"><i class="fa fa-gitlab" aria-hidden="true"></i>
{{ latest_minor_version }} {{ latest_minor_version }}
</a> </a>
{% if not latest_minor %}<br>{% trans "Update available" %}{% endif %} {% if not latest_minor %}<br>{% trans "Update available" %}{% endif %}
@@ -57,7 +57,7 @@
<li class="list-group-item list-group-item-{% if latest_patch %}success{% else %}danger{% endif %}"> <li class="list-group-item list-group-item-{% if latest_patch %}success{% else %}danger{% endif %}">
<h4 class="list-group-item-heading">{% trans "Latest Patch" %}</h4> <h4 class="list-group-item-heading">{% trans "Latest Patch" %}</h4>
<p class="list-group-item-text"> <p class="list-group-item-text">
<a href="{{ latest_patch_url }}" style="color:#000"><i class="fa fa-github" aria-hidden="true"></i> <a href="https://gitlab.com/allianceauth/allianceauth/tags" style="color:#000"><i class="fa fa-gitlab" aria-hidden="true"></i>
{{ latest_patch_version }} {{ latest_patch_version }}
</a> </a>
{% if not latest_patch %}<br>{% trans "Update available" %}{% endif %} {% if not latest_patch %}<br>{% trans "Update available" %}{% endif %}

View File

@@ -1,11 +1,12 @@
{% extends "allianceauth/base.html" %} {% extends "allianceauth/base.html" %}
{% load i18n %}
{% block page_title %}Help{% endblock page_title %} {% block page_title %}{% trans "Help" %}{% endblock page_title %}
{% block content %} {% block content %}
<div class="col-lg-12"> <div class="col-lg-12">
<h1 class="page-header text-center">Help</h1> <h1 class="page-header text-center">{% trans "Help" %}</h1>
<div class="container-fluid"> <div class="container-fluid">
<div class="embed-responsive embed-responsive-16by9"> <div class="embed-responsive embed-responsive-16by9">

View File

@@ -7,12 +7,12 @@
<li> <li>
<a class="{% navactive request 'authentication:dashboard' %}" <a class="{% navactive request 'authentication:dashboard' %}"
href="{% url 'authentication:dashboard' %}"> href="{% url 'authentication:dashboard' %}">
<i class="fa fa-dashboard fa-fw"></i>{% trans " Dashboard" %} <i class="fa fa-dashboard fa-fw"></i> {% trans "Dashboard" %}
</a> </a>
</li> </li>
<li> <li>
<a class="{% navactive request 'groupmanagement:groups' %}" href="{% url 'groupmanagement:groups' %}"> <a class="{% navactive request 'groupmanagement:groups' %}" href="{% url 'groupmanagement:groups' %}">
<i class="fa fa-cogs fa-fw fa-sitemap"></i>{% trans " Groups" %} <i class="fa fa-cogs fa-fw fa-sitemap"></i> {% trans "Groups" %}
</a> </a>
</li> </li>
@@ -20,7 +20,7 @@
<li> <li>
<a class="{% navactive request 'groupmanagement:management groupmanagement:membership groupmanagement:membership_list' %}" <a class="{% navactive request 'groupmanagement:management groupmanagement:membership groupmanagement:membership_list' %}"
href="{% url 'groupmanagement:management' %}"> href="{% url 'groupmanagement:management' %}">
<i class="fa fa-lock fa-sitemap fa-fw"></i>{% trans " Group Management" %} <i class="fa fa-lock fa-sitemap fa-fw"></i> {% trans "Group Management" %}
</a> </a>
</li> </li>
{% endif %} {% endif %}
@@ -30,7 +30,7 @@
<li> <li>
<a class="{% navactive request 'authentication:help' %}" <a class="{% navactive request 'authentication:help' %}"
href="{% url 'authentication:help' %}"> href="{% url 'authentication:help' %}">
<i class="fa fa-question fa-fw"></i>{% trans " Help" %} <i class="fa fa-question fa-fw"></i> {% trans "Help" %}
</a> </a>
</li> </li>
</ul> </ul>

View File

@@ -1,4 +1,4 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"></script>
{% if locale and LANGUAGE_CODE != 'en' %} {% if locale and LANGUAGE_CODE != 'en' %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/locale/{{ LANGUAGE_CODE }}.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/locale/{{ LANGUAGE_CODE }}.js"></script>
{% endif %} {% endif %}

View File

@@ -17,16 +17,16 @@ NOTIFICATION_CACHE_TIME = 300 # 5 minutes
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def get_github_tags(): def get_git_tags():
request = requests.get('https://api.github.com/repos/allianceauth/allianceauth/releases') request = requests.get('https://gitlab.com/api/v4/projects/allianceauth%2Fallianceauth/repository/tags')
request.raise_for_status() request.raise_for_status()
return request.json() return request.json()
def get_github_notification_issues(): def get_notification_issues():
# notification # notification
request = requests.get( request = requests.get(
'https://api.github.com/repos/allianceauth/allianceauth/issues?labels=announcement&state=all') 'https://gitlab.com/api/v4/projects/allianceauth%2Fallianceauth/issues?labels=announcement')
request.raise_for_status() request.raise_for_status()
return request.json() return request.json()
@@ -68,12 +68,12 @@ def get_notifications():
'notifications': list(), 'notifications': list(),
} }
try: try:
notifications = cache.get_or_set('github_notification_issues', get_github_notification_issues, notifications = cache.get_or_set('gitlab_notification_issues', get_notification_issues,
NOTIFICATION_CACHE_TIME) NOTIFICATION_CACHE_TIME)
# Limit notifications to those posted by repo owners and members # Limit notifications to those posted by repo owners and members
response['notifications'] += [n for n in notifications if n['author_association'] in ['OWNER', 'MEMBER']][:5] response['notifications'] += notifications[:5]
except requests.RequestException: except requests.RequestException:
logger.exception('Error while getting github notifications') logger.exception('Error while getting gitlab notifications')
return response return response
@@ -85,7 +85,7 @@ def get_version_info():
'current_version': __version__, 'current_version': __version__,
} }
try: try:
tags = cache.get_or_set('github_release_tags', get_github_tags, TAG_CACHE_TIME) tags = cache.get_or_set('git_release_tags', get_git_tags, TAG_CACHE_TIME)
current_ver = semver.Version.coerce(__version__) current_ver = semver.Version.coerce(__version__)
# Set them all to the current version to start # Set them all to the current version to start
@@ -102,7 +102,7 @@ def get_version_info():
}) })
for tag in tags: for tag in tags:
tag_name = tag.get('tag_name') tag_name = tag.get('name')
if tag_name[0] == 'v': if tag_name[0] == 'v':
# Strip 'v' off front of verison if it exists # Strip 'v' off front of verison if it exists
tag_name = tag_name[1:] tag_name = tag_name[1:]
@@ -114,24 +114,21 @@ def get_version_info():
if latest_major is None or tag_ver > latest_major: if latest_major is None or tag_ver > latest_major:
latest_major = tag_ver latest_major = tag_ver
response['latest_major_version'] = tag_name response['latest_major_version'] = tag_name
response['latest_major_url'] = tag['html_url']
if tag_ver.major > current_ver.major: if tag_ver.major > current_ver.major:
response['latest_major'] = False response['latest_major'] = False
elif tag_ver.major == current_ver.major: elif tag_ver.major == current_ver.major:
if latest_minor is None or tag_ver > latest_minor: if latest_minor is None or tag_ver > latest_minor:
latest_minor = tag_ver latest_minor = tag_ver
response['latest_minor_version'] = tag_name response['latest_minor_version'] = tag_name
response['latest_minor_url'] = tag['html_url']
if tag_ver.minor > current_ver.minor: if tag_ver.minor > current_ver.minor:
response['latest_minor'] = False response['latest_minor'] = False
elif tag_ver.minor == current_ver.minor: elif tag_ver.minor == current_ver.minor:
if latest_patch is None or tag_ver > latest_patch: if latest_patch is None or tag_ver > latest_patch:
latest_patch = tag_ver latest_patch = tag_ver
response['latest_patch_version'] = tag_name response['latest_patch_version'] = tag_name
response['latest_patch_url'] = tag['html_url']
if tag_ver.patch > current_ver.patch: if tag_ver.patch > current_ver.patch:
response['latest_patch'] = False response['latest_patch'] = False
except requests.RequestException: except requests.RequestException:
logger.exception('Error while getting github release tags') logger.exception('Error while getting gitlab release tags')
return response return response

View File

@@ -34,19 +34,21 @@ class TimerForm(forms.ModelForm):
structure_choices = [('POCO', 'POCO'), structure_choices = [('POCO', 'POCO'),
('I-HUB', 'I-HUB'), ('I-HUB', 'I-HUB'),
('TCU', 'TCU'),
('POS[S]', 'POS[S]'), ('POS[S]', 'POS[S]'),
('POS[M]', 'POS[M]'), ('POS[M]', 'POS[M]'),
('POS[L]', 'POS[L]'), ('POS[L]', 'POS[L]'),
('Citadel[M]', 'Citadel[M]'), ('Astrahus', 'Astrahus'),
('Citadel[L]', 'Citadel[L]'), ('Fortizar', 'Fortizar'),
('Citadel[XL]', 'Citadel[XL]'), ('Keepstar', 'Keepstar'),
('Engineering Complex[M]', 'Engineering Complex[M]'), ('Raitaru', 'Raitaru'),
('Engineering Complex[L]', 'Engineering Complex[L]'), ('Azbel', 'Azbel'),
('Engineering Complex[XL]', 'Engineering Complex[XL]'), ('Sotiyo', 'Sotiyo'),
('Refinery[M]', 'Refinery[M]'), ('Athanor', 'Athanor'),
('Refinery[L]', 'Refinery[L]'), ('Tatara', 'Tatara'),
('Station', 'Station'), ('Pharolux Cyno Beacon', 'Pharolux Cyno Beacon'),
('TCU', 'TCU'), ('Tenebrex Cyno Jammer', 'Tenebrex Cyno Jammer'),
('Ansiblex Jump Gate', 'Ansiblex Jump Gate'),
('Moon Mining Cycle', 'Moon Mining Cycle'), ('Moon Mining Cycle', 'Moon Mining Cycle'),
(_('Other'), _('Other'))] (_('Other'), _('Other'))]
objective_choices = [('Friendly', _('Friendly')), objective_choices = [('Friendly', _('Friendly')),

View File

@@ -18,7 +18,8 @@
<div class="col-lg-12 text-center"> <div class="col-lg-12 text-center">
<div class="label label-info text-left"> <div class="label label-info text-left">
<b>{% trans "Current Eve Time:" %} </b> <b>{% trans "Current Eve Time:" %} </b>
</div><div class="label label-info text-left" id="current-time"></div> </div>
<strong class="label label-info text-left" id="current-time"></strong>
</div> </div>
{% if corp_timers %} {% if corp_timers %}
<h4><b>{% trans "Corp Timers" %}</b></h4> <h4><b>{% trans "Corp Timers" %}</b></h4>
@@ -36,118 +37,128 @@
{% endif %} {% endif %}
</tr> </tr>
{% for timer in corp_timers %} {% for timer in corp_timers %}
{% ifequal timer.important True %} {% if timer.important == True %}
<tr class="danger"> <tr class="danger">
{% else %} {% else %}
<tr class="info"> <tr class="info">
{% endifequal %} {% endif %}
<td style="width:150px" class="text-center">{{ timer.details }}</td> <td style="width:150px" class="text-center">{{ timer.details }}</td>
<td class="text-center"> <td class="text-center">
{% ifequal timer.objective "Hostile" %} {% if timer.objective == "Hostile" %}
<div class="label label-danger"> <div class="label label-danger">
{% trans "Hostile" %} {% trans "Hostile" %}
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.objective "Friendly" %} {% if timer.objective == "Friendly" %}
<div class="label label-primary"> <div class="label label-primary">
{% trans "Friendly" %} {% trans "Friendly" %}
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.objective "Neutral" %} {% if timer.objective == "Neutral" %}
<div class="label label-default"> <div class="label label-default">
{% trans "Neutral" %} {% trans "Neutral" %}
</div> </div>
{% endifequal %} {% endif %}
</td> </td>
<td class="text-center"><a <td class="text-center"><a
href="http://evemaps.dotlan.net/system/{{ timer.system }}">{{ timer.system }} {{ timer.planet_moon }} </a> href="http://evemaps.dotlan.net/system/{{ timer.system }}">{{ timer.system }} {{ timer.planet_moon }} </a>
</td> </td>
<td class="text-center"> <td class="text-center">
{% ifequal timer.structure "I-HUB" %} {% if timer.structure == "POCO" %}
<div class="label label-info">
POCO
</div>
{% endif %}
{% if timer.structure == "I-HUB" %}
<div class="label label-warning"> <div class="label label-warning">
I-HUB I-HUB
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "POCO" %} {% if timer.structure == "TCU" %}
<div class="label label-success">
POCO
</div>
{% endifequal %}
{% ifequal timer.structure "POS[S]" %}
<div class="label label-info">
POS [S]
</div>
{% endifequal %}
{% ifequal timer.structure "POS[M]" %}
<div class="label label-info">
POS [M]
</div>
{% endifequal %}
{% ifequal timer.structure "POS[L]" %}
<div class="label label-info">
POS [L]
</div>
{% endifequal %}
{% ifequal timer.structure "Citadel[M]" %}
<div class="label label-danger">
Citadel [M]
</div>
{% endifequal %}
{% ifequal timer.structure "Citadel[L]" %}
<div class="label label-danger">
Citadel [L]
</div>
{% endifequal %}
{% ifequal timer.structure "Citadel[XL]" %}
<div class="label label-danger">
Citadel [XL]
</div>
{% endifequal %}
{% ifequal timer.structure "Engineering Complex[M]" %}
<div class="label label-warning">
Engineering Complex [M]
</div>
{% endifequal %}
{% ifequal timer.structure "Engineering Complex[L]" %}
<div class="label label-warning">
Engineering Complex [L]
</div>
{% endifequal %}
{% ifequal timer.structure "Engineering Complex[XL]" %}
<div class="label label-warning">
Engineering Complex [XL]
</div>
{% endifequal %}
{% ifequal timer.structure "Station" %}
<div class="label label-danger">
Station
</div>
{% endifequal %}
{% ifequal timer.structure "TCU" %}
<div class="label label-danger"> <div class="label label-danger">
TCU TCU
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Refinery[M]" %} {% if timer.structure == "POS[S]" %}
<div class="label label-warning"> <div class="label label-info">
Refinery [M] POS [S]
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Refinery[L]" %} {% if timer.structure == "POS[M]" %}
<div class="label label-warning"> <div class="label label-info">
Refinery [L] POS [M]
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Moon Mining Cycle" %} {% if timer.structure == "POS[L]" %}
<div class="label label-info">
POS [L]
</div>
{% endif %}
{% if timer.structure == "Citadel[M]" or timer.structure == "Astrahus" %}
<div class="label label-danger">
Astrahus
</div>
{% endif %}
{% if timer.structure == "Citadel[L]" or timer.structure == "Fortizar" %}
<div class="label label-danger">
Fortizar
</div>
{% endif %}
{% if timer.structure == "Citadel[XL]" or timer.structure == "Keepstar" %}
<div class="label label-danger">
Keepstar
</div>
{% endif %}
{% if timer.structure == "Engineering Complex[M]" or timer.structure == "Raitaru" %}
<div class="label label-warning">
Raitaru
</div>
{% endif %}
{% if timer.structure == "Engineering Complex[L]" or timer.structure == "Azbel" %}
<div class="label label-warning">
Azbel
</div>
{% endif %}
{% if timer.structure == "Engineering Complex[XL]" or timer.structure == "Sotiyo" %}
<div class="label label-warning">
Sotiyo
</div>
{% endif %}
{% if timer.structure == "Refinery[M]" or timer.structure == "Athanor" %}
<div class="label label-warning">
Athanor
</div>
{% endif %}
{% if timer.structure == "Refinery[L]" or timer.structure == "Tatara"%}
<div class="label label-warning">
Tatara
</div>
{% endif %}
{% if timer.structure == "Cyno Beacon" or timer.structure == "Pharolux Cyno Beacon" %}
<div class="label label-warning">
Cyno Beacon
</div>
{% endif %}
{% if timer.structure == "Cyno Jammer" or timer.structure == "Tenebrex Cyno Jammer" %}
<div class="label label-warning">
Tenebrex Cyno Jammer
</div>
{% endif %}
{% if timer.structure == "Jump Gate" or timer.structure == "Ansiblex Jump Gate" %}
<div class="label label-warning">
Ansiblex Jump Gate
</div>
{% endif %}
{% if timer.structure == "Moon Mining Cycle" %}
<div class="label label-success"> <div class="label label-success">
Moon Mining Cycle Moon Mining Cycle
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Other" %} {% if timer.structure == "Other" %}
<div class="label label-default"> <div class="label label-default">
Other Other
</div> </div>
{% endifequal %} {% endif %}
</td> </td>
<td class="text-center" nowrap>{{ timer.eve_time | date:"Y-m-d H:i" }}</td> <td class="text-center" nowrap>{{ timer.eve_time | date:"Y-m-d H:i" }}</td>
<td class="text-center" nowrap> <td class="text-center" nowrap>
@@ -185,118 +196,128 @@
{% endif %} {% endif %}
</tr> </tr>
{% for timer in future_timers %} {% for timer in future_timers %}
{% ifequal timer.important True %} {% if timer.important == True %}
<tr class="danger"> <tr class="danger">
{% else %} {% else %}
<tr class="info"> <tr class="info">
{% endifequal %} {% endif %}
<td style="width:150px" class="text-center">{{ timer.details }}</td> <td style="width:150px" class="text-center">{{ timer.details }}</td>
<td class="text-center"> <td class="text-center">
{% ifequal timer.objective "Hostile" %} {% if timer.objective == "Hostile" %}
<div class="label label-danger"> <div class="label label-danger">
{% trans "Hostile" %} {% trans "Hostile" %}
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.objective "Friendly" %} {% if timer.objective == "Friendly" %}
<div class="label label-primary"> <div class="label label-primary">
{% trans "Friendly" %} {% trans "Friendly" %}
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.objective "Neutral" %} {% if timer.objective == "Neutral" %}
<div class="label label-default"> <div class="label label-default">
{% trans "Neutral" %} {% trans "Neutral" %}
</div> </div>
{% endifequal %} {% endif %}
</td> </td>
<td class="text-center"> <td class="text-center">
<a href="http://evemaps.dotlan.net/system/{{ timer.system }}">{{ timer.system }} {{ timer.planet_moon }}</a> <a href="http://evemaps.dotlan.net/system/{{ timer.system }}">{{ timer.system }} {{ timer.planet_moon }}</a>
</td> </td>
<td class="text-center"> <td class="text-center">
{% ifequal timer.structure "I-HUB" %} {% if timer.structure == "POCO" %}
<div class="label label-warning"> <div class="label label-info">
I-HUB POCO
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "POCO" %} {% if timer.structure == "I-HUB" %}
<div class="label label-success"> <div class="label label-warning">
POCO I-HUB
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "POS[S]" %} {% if timer.structure == "TCU" %}
<div class="label label-info"> <div class="label label-danger">
POS [S] TCU
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "POS[M]" %} {% if timer.structure == "POS[S]" %}
<div class="label label-info"> <div class="label label-info">
POS [M] POS [S]
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "POS[L]" %} {% if timer.structure == "POS[M]" %}
<div class="label label-info"> <div class="label label-info">
POS [L] POS [M]
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Citadel[M]" %} {% if timer.structure == "POS[L]" %}
<div class="label label-danger"> <div class="label label-info">
Citadel [M] POS [L]
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Citadel[L]" %} {% if timer.structure == "Citadel[M]" or timer.structure == "Astrahus" %}
<div class="label label-danger"> <div class="label label-danger">
Citadel [L] Astrahus
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Citadel[XL]" %} {% if timer.structure == "Citadel[L]" or timer.structure == "Fortizar" %}
<div class="label label-danger"> <div class="label label-danger">
Citadel [XL] Fortizar
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Engineering Complex[M]" %} {% if timer.structure == "Citadel[XL]" or timer.structure == "Keepstar" %}
<div class="label label-warning"> <div class="label label-danger">
Engineering Complex [M] Keepstar
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Engineering Complex[L]" %} {% if timer.structure == "Engineering Complex[M]" or timer.structure == "Raitaru" %}
<div class="label label-warning"> <div class="label label-warning">
Engineering Complex [L] Raitaru
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Engineering Complex[XL]" %} {% if timer.structure == "Engineering Complex[L]" or timer.structure == "Azbel" %}
<div class="label label-warning"> <div class="label label-warning">
Engineering Complex [XL] Azbel
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Station" %} {% if timer.structure == "Engineering Complex[XL]" or timer.structure == "Sotiyo" %}
<div class="label label-danger"> <div class="label label-warning">
Station Sotiyo
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "TCU" %} {% if timer.structure == "Refinery[M]" or timer.structure == "Athanor" %}
<div class="label label-danger"> <div class="label label-warning">
TCU Athanor
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Refinery[M]" %} {% if timer.structure == "Refinery[L]" or timer.structure == "Tatara" %}
<div class="label label-warning"> <div class="label label-warning">
Refinery [M] Tatara
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Refinery[L]" %} {% if timer.structure == "Cyno Beacon" or timer.structure == "Pharolux Cyno Beacon" %}
<div class="label label-warning"> <div class="label label-warning">
Refinery [L] Pharolux Cyno Beacon
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Moon Mining Cycle" %} {% if timer.structure == "Cyno Jammer" or timer.structure == "Tenebrex Cyno Jammer" %}
<div class="label label-success"> <div class="label label-warning">
Moon Mining Cycle Tenebrex Cyno Jammer
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Other" %} {% if timer.structure == "Jump Gate" or timer.structure == "Ansiblex Jump Gate" %}
<div class="label label-default"> <div class="label label-warning">
Other Ansiblex Jump Gate
</div> </div>
{% endifequal %} {% endif %}
{% if timer.structure == "Moon Mining Cycle" %}
<div class="label label-success">
Moon Mining Cycle
</div>
{% endif %}
{% if timer.structure == "Other" %}
<div class="label label-default">
Other
</div>
{% endif %}
</td> </td>
<td class="text-center" nowrap>{{ timer.eve_time | date:"Y-m-d H:i" }}</td> <td class="text-center" nowrap>{{ timer.eve_time | date:"Y-m-d H:i" }}</td>
<td class="text-center" nowrap> <td class="text-center" nowrap>
@@ -336,118 +357,128 @@
{% endif %} {% endif %}
</tr> </tr>
{% for timer in past_timers %} {% for timer in past_timers %}
{% ifequal timer.important True %} {% if timer.important == True %}
<tr class="danger"> <tr class="danger">
{% else %} {% else %}
<tr class="info"> <tr class="info">
{% endifequal %} {% endif %}
<td style="width:150px" class="text-center">{{ timer.details }}</td> <td style="width:150px" class="text-center">{{ timer.details }}</td>
<td class="text-center"> <td class="text-center">
{% ifequal timer.objective "Hostile" %} {% if timer.objective == "Hostile" %}
<div class="label label-danger"> <div class="label label-danger">
{% trans "Hostile" %} {% trans "Hostile" %}
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.objective "Friendly" %} {% if timer.objective == "Friendly" %}
<div class="label label-primary"> <div class="label label-primary">
{% trans "Friendly" %} {% trans "Friendly" %}
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.objective "Neutral" %} {% if timer.objective == "Neutral" %}
<div class="label label-default"> <div class="label label-default">
{% trans "Neutral" %} {% trans "Neutral" %}
</div> </div>
{% endifequal %} {% endif %}
</td> </td>
<td class="text-center"> <td class="text-center">
<a href="http://evemaps.dotlan.net/system/{{ timer.system }}">{{ timer.system }} {{ timer.planet_moon }}</a> <a href="http://evemaps.dotlan.net/system/{{ timer.system }}">{{ timer.system }} {{ timer.planet_moon }}</a>
</td> </td>
<td class="text-center"> <td class="text-center">
{% ifequal timer.structure "I-HUB" %} {% if timer.structure == "POCO" %}
<div class="label label-warning"> <div class="label label-info">
I-HUB POCO
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "POCO" %} {% if timer.structure == "I-HUB" %}
<div class="label label-success"> <div class="label label-warning">
POCO I-HUB
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "POS[S]" %} {% if timer.structure == "TCU" %}
<div class="label label-info"> <div class="label label-danger">
POS [S] TCU
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "POS[M]" %} {% if timer.structure == "POS[S]" %}
<div class="label label-info"> <div class="label label-info">
POS [M] POS [S]
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "POS[L]" %} {% if timer.structure == "POS[M]" %}
<div class="label label-info"> <div class="label label-info">
POS [L] POS [M]
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Citadel[M]" %} {% if timer.structure == "POS[L]" %}
<div class="label label-danger"> <div class="label label-info">
Citadel [M] POS [L]
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Citadel[L]" %} {% if timer.structure == "Citadel[M]" or timer.structure == "Astrahus" %}
<div class="label label-danger"> <div class="label label-danger">
Citadel [L] Astrahus
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Citadel[XL]" %} {% if timer.structure == "Citadel[L]" or timer.structure == "Fortizar" %}
<div class="label label-danger"> <div class="label label-danger">
Citadel [XL] Fortizar
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Engineering Complex[M]" %} {% if timer.structure == "Citadel[XL]" or timer.structure == "Keepstar" %}
<div class="label label-warning"> <div class="label label-danger">
Engineering Complex [M] Keepstar
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Engineering Complex[L]" %} {% if timer.structure == "Engineering Complex[M]" or timer.structure == "Raitaru" %}
<div class="label label-warning"> <div class="label label-warning">
Engineering Complex [L] Raitaru
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Engineering Complex[XL]" %} {% if timer.structure == "Engineering Complex[L]" or timer.structure == "Azbel" %}
<div class="label label-warning"> <div class="label label-warning">
Engineering Complex [XL] Azbel
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Station" %} {% if timer.structure == "Engineering Complex[XL]" or timer.structure == "Sotiyo" %}
<div class="label label-danger"> <div class="label label-warning">
Station Sotiyo
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "TCU" %} {% if timer.structure == "Refinery[M]" or timer.structure == "Athanor" %}
<div class="label label-danger"> <div class="label label-warning">
TCU Athanor
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Refinery[M]" %} {% if timer.structure == "Refinery[L]" or timer.structure == "Tatara" %}
<div class="label label-warning"> <div class="label label-warning">
Refinery [M] Tatara
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Refinery[L]" %} {% if timer.structure == "Cyno Beacon" or timer.structure == "Pharolux Cyno Beacon" %}
<div class="label label-warning"> <div class="label label-warning">
Refinery [L] Pharolux Cyno Beacon
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Moon Mining Cycle" %} {% if timer.structure == "Cyno Jammer" or timer.structure == "Tenebrex Cyno Jammer" %}
<div class="label label-success"> <div class="label label-warning">
Moon Mining Cycle Tenebrex Cyno Jammer
</div> </div>
{% endifequal %} {% endif %}
{% ifequal timer.structure "Other" %} {% if timer.structure == "Jump Gate" or timer.structure == "Ansiblex Jump Gate" %}
<div class="label label-default"> <div class="label label-warning">
Other Ansiblex Jump Gate
</div> </div>
{% endifequal %} {% endif %}
{% if timer.structure == "Moon Mining Cycle" %}
<div class="label label-success">
Moon Mining Cycle
</div>
{% endif %}
{% if timer.structure == "Other" %}
<div class="label label-default">
Other
</div>
{% endif %}
</td> </td>
<td class="text-center" nowrap>{{ timer.eve_time | date:"Y-m-d H:i" }}</td> <td class="text-center" nowrap>{{ timer.eve_time | date:"Y-m-d H:i" }}</td>
<td class="text-center" nowrap> <td class="text-center" nowrap>
@@ -555,7 +586,7 @@
} }
function updateClock() { function updateClock() {
document.getElementById("current-time").innerHTML = "<b>" + moment().format('LLLL') + "</b>"; document.getElementById("current-time").innerHTML = getCurrentEveTimeString();
} }
</script> </script>
{% endblock content %} {% endblock content %}

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -66,6 +66,17 @@ Clicking on the blue eye will take you to the group member management screen. He
![Group overview](/_static/images/features/group-member-management.png) ![Group overview](/_static/images/features/group-member-management.png)
### Group Audit Log
Whenever a user Joins, Leaves, or is Removed from a group, this is logged. To find the audit log for a given group, click the light-blue button to the right of the Group Member Management (blue eye) button.
These logs contain the Date and Time the action was taken (in EVE/UTC), the user which submitted the request being acted upon (requestor), the user's main character, the type of request (join, leave or removed), the action taken (accept, reject or remove), and the user that took the action (actor).
![Audit Log Example](/_static/images/features/group_audit_log.png)
```eval_rst
.. note::
There is no tracking for "Open" groups as members are able to freely join/leave these groups.
```
## Group Leaders ## Group Leaders

View File

@@ -2,7 +2,7 @@
```eval_rst ```eval_rst
.. tip:: .. tip::
If you are uncomfortable with Linux permissions follow the steps below as the root user. If you are uncomfortable with Linux permissions follow the steps below as the root user.
``` ```
## Dependencies ## Dependencies
@@ -12,7 +12,7 @@ Alliance Auth can be installed on any operating system. Dependencies are provide
```eval_rst ```eval_rst
.. hint:: .. hint::
CentOS: A few packages are included in a non-default repository. Add it and update the package lists. :: CentOS: A few packages are included in a non-default repository. Add it and update the package lists. ::
yum -y install https://centos7.iuscommunity.org/ius-release.rpm yum -y install https://centos7.iuscommunity.org/ius-release.rpm
yum update yum update
``` ```
@@ -39,7 +39,7 @@ Ubuntu:
CentOS: CentOS:
yum install mariadb-server mariadb-devel mariadb yum install mariadb-server mariadb-devel mariadb-shared mariadb
```eval_rst ```eval_rst
.. note:: .. note::
@@ -61,7 +61,7 @@ CentOS:
```eval_rst ```eval_rst
.. important:: .. important::
CentOS: Make sure Redis is running before continuing. :: CentOS: Make sure Redis is running before continuing. ::
systemctl enable redis.service systemctl enable redis.service
systemctl start redis.service systemctl start redis.service
``` ```
@@ -74,6 +74,19 @@ Alliance Auth needs a MySQL user account and database. Open an SQL shell with `m
CREATE DATABASE alliance_auth CHARACTER SET utf8; CREATE DATABASE alliance_auth CHARACTER SET utf8;
GRANT ALL PRIVILEGES ON alliance_auth . * TO 'allianceserver'@'localhost'; GRANT ALL PRIVILEGES ON alliance_auth . * TO 'allianceserver'@'localhost';
Add timezone tables to your mysql installation:
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
```eval_rst
.. note::
You may see errors when you add the timezone tables. To make sure that they were correctly added run the following commands and check for the ``time_zone`` tables::
mysql -u root -p
use mysql;
show tables;
```
Close the SQL shell and secure your database server with the `mysql_secure_installation` command. Close the SQL shell and secure your database server with the `mysql_secure_installation` command.
## Auth Install ## Auth Install
@@ -106,7 +119,7 @@ Create a Python virtual environment and put it somewhere convenient (e.g. `/home
A virtual environment provides support for creating a lightweight "copy" of Python with their own site directories. Each virtual environment has its own Python binary (allowing creation of environments with various Python versions) and can have its own independent set of installed Python packages in its site directories. You can read more about virtual environments on the Python_ docs. A virtual environment provides support for creating a lightweight "copy" of Python with their own site directories. Each virtual environment has its own Python binary (allowing creation of environments with various Python versions) and can have its own independent set of installed Python packages in its site directories. You can read more about virtual environments on the Python_ docs.
.. _Python: https://docs.python.org/3/library/venv.html .. _Python: https://docs.python.org/3/library/venv.html
``` ```
Activate the virtualenv using `source /home/allianceserver/venv/auth/bin/activate`. Note the `/bin/activate` on the end of the path. Activate the virtualenv using `source /home/allianceserver/venv/auth/bin/activate`. Note the `/bin/activate` on the end of the path.
```eval_rst ```eval_rst
@@ -131,7 +144,7 @@ Django needs to install models to the database before it can start.
python /home/allianceserver/myauth/manage.py migrate python /home/allianceserver/myauth/manage.py migrate
Now we need to round up all the static files required to render templates. Make a directory to serve them from and populate it. Now we need to round up all the static files required to render templates. Make a directory to serve them from and populate it.
mkdir -p /var/www/myauth/static mkdir -p /var/www/myauth/static
python /home/allianceserver/myauth/manage.py collectstatic python /home/allianceserver/myauth/manage.py collectstatic
@@ -182,7 +195,7 @@ You can check the status of the processes with `supervisorctl status`. Logs from
```eval_rst ```eval_rst
.. note:: .. note::
Any time the code or your settings change you'll need to restart Gunicorn and Celery. :: Any time the code or your settings change you'll need to restart Gunicorn and Celery. ::
supervisorctl restart myauth: supervisorctl restart myauth:
``` ```
@@ -202,10 +215,10 @@ If you intend to use this account as your personal auth account you need to add
## Updating ## Updating
Periodically [new releases](https://github.com/allianceauth/allianceauth/releases/) are issued with bug fixes and new features. To update your install, simply activate your virtual environment and update with `pip install --upgrade allianceauth`. Be sure to read the release notes which will highlight changes. Periodically [new releases](https://gitlab.com/allianceauth/allianceauth/tags) are issued with bug fixes and new features. To update your install, simply activate your virtual environment and update with `pip install --upgrade allianceauth`. Be sure to read the release notes which will highlight changes.
Some releases come with changes to settings: update your project's settings with `allianceauth update /home/allianceserver/myauth`. Some releases come with changes to settings: update your project's settings with `allianceauth update /home/allianceserver/myauth`.
Some releases come with new or changed models. Update your database to reflect this with `python /home/allianceserver/myauth/manage.py migrate`. Some releases come with new or changed models. Update your database to reflect this with `python /home/allianceserver/myauth/manage.py migrate`.
Always restart Celery and Gunicorn after updating. Always restart Celery and Gunicorn after updating.

View File

@@ -56,7 +56,7 @@ Put comma-separated IDs into the brackets and the migration will create states w
If you used member/blue group names other than the standard "Member" and "Blue" you can enter settings to have the member/blue states created through this migration take these names. If you used member/blue group names other than the standard "Member" and "Blue" you can enter settings to have the member/blue states created through this migration take these names.
- `DEFAULT_AUTH_GROUP = ""` the desired name of the "Member" state - `DEFAULT_AUTH_GROUP = ""` the desired name of the "Member" state
- `DEFAULT_BLUE_GROUP = ""` the desired name of the "Blue" state - `DEFAULT_BLUE_GROUP = ""` the desired name of the "Blue" state
Any permissions assigned to these groups will be copied to the state replacing them. Because these groups are no longer managed they pose a security risk and so are deleted at the end of the migration automatically. Any permissions assigned to these groups will be copied to the state replacing them. Because these groups are no longer managed they pose a security risk and so are deleted at the end of the migration automatically.
@@ -82,4 +82,4 @@ A similar process can be used to ensure users who may have lost service permissi
## Help ## Help
If something goes wrong during the migration reach out for help on [Gitter](https://gitter.im/R4stl1n/allianceauth) or open an [issue](https://github.com/allianceauth/allianceauth/issues). If something goes wrong during the migration reach out for help on [Gitter](https://gitter.im/R4stl1n/allianceauth) or open an [issue](https://gitlab.com/allianceauth/allianceauth/issues).

View File

@@ -1,161 +1,7 @@
# Alliance Market # Alliance Market
## Dependencies ## Deprecation
Alliance Market requires PHP installed in your web server. Apache has `mod_php`, NGINX requires `php-fpm`.
## Prepare Your Settings Alliance Market relies on the now non-functional XML API.
In your auth project's settings file, do the following:
- Add `'allianceauth.services.modules.market',` to your `INSTALLED_APPS` list
- Append the following to the bottom of the settings file
Please remove this service data with `python manage.py migrate appname zero` and then remove from your `INSTALLED_APPS` list.
# Alliance Market
MARKET_URL = ''
DATABASES['market'] = {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'alliance_market',
'USER': 'allianceserver-market',
'PASSWORD': 'password',
'HOST': '127.0.0.1',
'PORT': '3306',
}
## Setup Alliance Market
Alliance Market needs a database. Create one in MySQL/MariaDB. Default name is `alliance_market`:
mysql -u root -p
create database alliance_market;
grant all privileges on alliance_market . * to 'allianceserver'@'localhost';
exit;
Install required packages to clone the repository:
apt-get install mercurial meld
Change to the web folder:
cd /var/www
Now clone the repository
hg clone https://bitbucket.org/krojew/evernus-alliance-market
Make cache and log directories
mkdir evernus-alliance-market/app/cache
mkdir evernus-alliance-market/app/logs
chmod -R 777 evernus-alliance-market/app/cache
chmod -R 777 evernus-alliance-market/app/logs
Change ownership to apache
chown -R www-data:www-data evernus-alliance-market
Enter directory
cd evernus-alliance-market
Set environment variable
export SYMFONY_ENV=prod
Copy configuration
cp app/config/parameters.yml.dist app/config/parameters.yml
Edit, changing the following:
- `database_name` to `alliance_market`
- `database_user` to your MySQL user (usually `allianceserver`)
- `database_password` to your MySQL user password
- email settings, eg Gmail/Mailgun etc.
Edit `app/config/config.yml` and add the following:
services:
fos_user.doctrine_registry:
alias: doctrine
Install composer [as per these instructions.](https://getcomposer.org/download/)
Update dependencies.
php composer.phar update --optimize-autoloader
Prepare the cache:
php app/console cache:clear --env=prod --no-debug
Dump assets:
php app/console assetic:dump --env=prod --no-debug
Create DB entries
php app/console doctrine:schema:update --force
Install SDE:
php app/console evernus:update:sde
Configure your web server to serve alliance market.
A minimal Apache config might look like:
<VirtualHost *:80>
ServerName market.example.com
DocumentRoot /var/www/evernus-alliance-market/web
<Directory "/var/www/evernus-alliance-market/web/">
DirectoryIndex app.php
Require all granted
AllowOverride all
</Directory>
</VirtualHost>
A minimal Nginx config might look like:
server {
listen 80;
server_name market.example.com;
root /var/www/evernus-alliance-market/web;
index app.php;
access_log /var/logs/market.access.log;
# strip app.php/ prefix if it is present
rewrite ^/app\.php/?(.*)$ /$1 permanent;
location / {
index app.php;
try_files $uri @rewriteapp;
}
location @rewriteapp {
rewrite ^(.*)$ /app.php/$1 last;
}
# pass the PHP scripts to FastCGI server from upstream phpfcgi
location ~ ^/(app|app_dev|config)\.php(/|$) {
fastcgi_pass 127.0.0.1:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
}
location ~ /\.ht {
deny all;
}
}
Once again, set cache permissions:
chown -R www-data:www-data app/
Add a user account through auth, then make it a superuser:
php app/console fos:user:promote your_username --super
Now edit your auth project's settings file and fill in the web URL to your market as well as the database details.
Finally run migrations and restart Gunicorn and Celery.

View File

@@ -22,7 +22,7 @@ Now two packages need to be installed:
apt-get install python-software-properties mumble-server apt-get install python-software-properties mumble-server
Download the appropriate authenticator release from [the authenticator repository](https://github.com/allianceauth/mumble-authenticator) and install the python dependencies for it: Download the appropriate authenticator release from [the authenticator repository](https://gitlab.com/allianceauth/mumble-authenticator) and install the python dependencies for it:
pip install -r requirements.txt pip install -r requirements.txt
@@ -34,6 +34,7 @@ Mumble ships with a configuration file that needs customization. By default it
REQUIRED: To enable the ICE authenticator, edit the following: REQUIRED: To enable the ICE authenticator, edit the following:
- `icesecretwrite=MY_CLEVER_PASSWORD`, obviously choosing a secure password - `icesecretwrite=MY_CLEVER_PASSWORD`, obviously choosing a secure password
- ensure the line containing `Ice="tcp -h 127.0.0.1 -p 6502"` is uncommented
By default mumble operates on SQLite which is fine, but slower than a dedicated MySQL server. To customize the database, edit the following: By default mumble operates on SQLite which is fine, but slower than a dedicated MySQL server. To customize the database, edit the following:
@@ -46,7 +47,7 @@ By default mumble operates on SQLite which is fine, but slower than a dedicated
To name your root channel, uncomment and set `registerName=` to whatever cool name you want To name your root channel, uncomment and set `registerName=` to whatever cool name you want
Save and close the file (control + O, control + X). Save and close the file.
To get Mumble superuser account credentials, run the following: To get Mumble superuser account credentials, run the following:
@@ -80,7 +81,21 @@ Test your configuration by starting it: `python authenticator.py`
## Running the Authenticator ## Running the Authenticator
The authenticator needs to be running 24/7 to validate users on Mumble. You should check the [supervisor docs](../auth/supervisor.md) on how to achieve this. The authenticator needs to be running 24/7 to validate users on Mumble. This can be achieved by adding a section to your auth project's supervisor config file like the following example:
```
[program:authenticator]
command=/path/to/venv/bin/python authenticator.py
directory=/path/to/authenticator/directory/
user=allianceserver
stdout_logfile=/path/to/authenticator/directory/authenticator.log
stderr_logfile=/path/to/authenticator/directory/authenticator.log
autostart=true
autorestart=true
startsecs=10
priority=998
```
Note that groups will only be created on Mumble automatically when a user joins who is in the group. Note that groups will only be created on Mumble automatically when a user joins who is in the group.

View File

@@ -58,7 +58,7 @@ Nginx: `chown -R nginx:nginx /var/www/forums`
```eval_rst ```eval_rst
.. tip:: .. tip::
Nginx: Some distributions use the ``www-data:www-data`` user:group instead of ``nginx:nginx``. If you run into problems with permissions try it instead. Nginx: Some distributions use the ``www-data:www-data`` user:group instead of ``nginx:nginx``. If you run into problems with permissions try it instead.
.. ..
``` ```
@@ -103,7 +103,7 @@ A minimal Nginx config file might look like:
} }
} }
Enter your forum's web address as the `PHPBB3_URL` setting in your auth project's settings file. Enter your forum's web address as the `PHPBB3_URL` setting in your auth project's settings file.
### Web Install ### Web Install
Navigate to your forums web address where you will be presented with an installer. Navigate to your forums web address where you will be presented with an installer.
@@ -144,5 +144,15 @@ You can allow members to overwrite the portrait with a custom image if desired.
![location of change avatar setting](/_static/images/installation/services/phpbb3/avatar_permissions.png) ![location of change avatar setting](/_static/images/installation/services/phpbb3/avatar_permissions.png)
## Setting the default theme
Users generated via Alliance Auth do not have a default theme set. You will need to set this on the phpbb_users table in SQL
mysql -u root -p
use alliance_forum;
alter table phpbb_users change user_style user_style int not null default 1
If you would like to use a theme that is NOT prosilver or theme "1". You will need to deactivate prosilver, this will then fall over to the set forum wide default.
### Prepare Auth ### Prepare Auth
Once settings have been configured, run migrations and restart Gunicorn and Celery. Once settings have been configured, run migrations and restart Gunicorn and Celery.

View File

@@ -2,17 +2,17 @@
## Something broken? Stuck on an issue? Can't get it set up? ## Something broken? Stuck on an issue? Can't get it set up?
Start by checking the [issues](https://github.com/allianceauth/allianceauth/issues?q=is%3Aissue) - especially closed ones. Start by checking the [issues](https://gitlab.com/allianceauth/allianceauth/issues?scope=all&utf8=%E2%9C%93&state=all&search=my+issue) - especially closed ones.
No answer? No answer?
- open an [issue](https://github.com/allianceauth/allianceauth/issues) - open an [issue](https://gitlab.com/allianceauth/allianceauth/issues)
- harass us on [gitter](https://gitter.im/R4stl1n/allianceauth) - harass us on [gitter](https://gitter.im/R4stl1n/allianceauth)
## Logging ## Logging
In its default configuration your auth project logs INFO and above messages to myauth/log/allianceauth.log. If you're encountering issues it's a good idea to view DEBUG messages as these greatly assist the troubleshooting process. These are printed to the console with manually starting the webserver via `python manage.py runserver`. In its default configuration your auth project logs INFO and above messages to myauth/log/allianceauth.log. If you're encountering issues it's a good idea to view DEBUG messages as these greatly assist the troubleshooting process. These are printed to the console with manually starting the webserver via `python manage.py runserver`.
To record DEBUG messages in the log file, alter a setting in your auth project's settings file: `LOGGING['handlers']['log_file']['level'] = 'DEBUG'`. After restarting gunicorn and celery your log file will record all logging messages. To record DEBUG messages in the log file, alter a setting in your auth project's settings file: `LOGGING['handlers']['log_file']['level'] = 'DEBUG'`. After restarting gunicorn and celery your log file will record all logging messages.
## Common Problems ## Common Problems

View File

@@ -12,21 +12,22 @@ install_requires = [
'requests-oauthlib', 'requests-oauthlib',
'semantic_version', 'semantic_version',
'redis', 'redis<=2.10.6',
'celery>=4.0.2', 'celery>=4.0.2,<4.3.0',
'celery_once', 'celery_once',
'django>=1.11', 'django>=2.0',
'django-bootstrap-form', 'django-bootstrap-form',
'django-registration==2.4', 'django-registration==2.4',
'django-sortedm2m', 'django-sortedm2m',
'django-redis-cache>=1.7.1', 'django-redis-cache==1.8.1',
'django-celery-beat', 'django-celery-beat<=1.1.1',
'openfire-restapi', 'openfire-restapi',
'sleekxmpp', 'sleekxmpp',
'adarnauth-esi>=1.4.10,<2.0', 'adarnauth-esi>=1.4.10,<2.0',
'kombu<=4.3.0',
] ]
testing_extras = [ testing_extras = [
@@ -50,7 +51,7 @@ setup(
python_requires='~=3.4', python_requires='~=3.4',
license='GPLv2', license='GPLv2',
packages=['allianceauth'], packages=['allianceauth'],
url='https://github.com/allianceauth/allianceauth', url='https://gitlab.com/allianceauth/allianceauth',
zip_safe=False, zip_safe=False,
include_package_data=True, include_package_data=True,
entry_points=""" entry_points="""

View File

@@ -17,4 +17,6 @@ deps=
py37: https://github.com/yaml/pyyaml/zipball/master#egg=pyyaml py37: https://github.com/yaml/pyyaml/zipball/master#egg=pyyaml
py37: https://github.com/celery/kombu/zipball/master#egg=kombu py37: https://github.com/celery/kombu/zipball/master#egg=kombu
install_command = pip install -e ".[testing]" -U {opts} {packages} install_command = pip install -e ".[testing]" -U {opts} {packages}
commands=coverage run runtests.py -v 2 commands =
coverage run runtests.py -v 2
coverage report -m