Compare commits

...

58 Commits

Author SHA1 Message Date
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
colcrunch
c8ad1dcc7a Merge pull request #2 from allianceauth/master
sync
2018-05-02 20:01:42 -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
45 changed files with 983 additions and 759 deletions

2
.gitignore vendored
View File

@@ -62,3 +62,5 @@ celerybeat-schedule
#pycharm #pycharm
.idea/* .idea/*
/nbproject/

41
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,41 @@
# 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-dj111:
<<: *job_definition
image: python:3.6-stretch
script:
- export TOXENV=py36-dj111
- tox
py36-dj20:
<<: *job_definition
image: python:3.6-stretch
script:
- export TOXENV=py36-dj20
- tox

View File

@@ -3,8 +3,9 @@ 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) [![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)
[![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.

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.2' __version__ = '2.1b1'
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

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

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

@@ -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,6 +13,11 @@ 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):

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

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

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

@@ -1,256 +1,254 @@
{% extends "allianceauth/base.html" %} {% extends "allianceauth/base.html" %}
{% load bootstrap %} {% load bootstrap %}
{% load staticfiles %} {% load staticfiles %}
{% load i18n %} {% load i18n %}
{% block page_title %}FleetUp{% endblock page_title %} {% block page_title %}FleetUp{% endblock page_title %}
{% 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">
<div class="panel-heading"> <div class="panel-heading">
<h3 class="panel-title"><b>{{ start.subject }}</b></h3> <h3 class="panel-title"><b>{{ start.subject }}</b></h3>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<table class="table table-condensed"> <table class="table table-condensed">
<tr> <tr>
<th class="col-md-6">{% trans "Start" %}</th> <th class="col-md-6">{% trans "Start" %}</th>
<th class="col-md-6">{% trans "End" %}</th> <th class="col-md-6">{% trans "End" %}</th>
</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>
<td class="col-md-6"> <td class="col-md-6">
<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> <th class="col-md-4">{% trans "Doctrine" %}</th>
<th class="col-md-4">{% trans "Doctrine" %}</th> <th class="col-md-2">{% trans "Organizer" %}</th>
<th class="col-md-2">{% trans "Organizer" %}</th> <th class="col-md-2">{% trans "URL" %}</th>
<th class="col-md-2">{% trans "URL" %}</th> </tr>
</tr> <tr>
<tr> <td>
<td> {{ start.location }} - {{ start.location_info }} <a href="http://evemaps.dotlan.net/system/{{ start.location }}" target="_blank" class="label label-success">Dotlan</a>
{{ start.location }} - {{ start.location_info }} <a href="http://evemaps.dotlan.net/system/{{ start.location }}" target="_blank" class="label label-success">Dotlan</a> </td>
</td> <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 %} </td>
</td> <td>
<td> {{ start.organizer }}
{{ start.organizer }} </td>
</td> <td>
<td> {% ifequal start.url "" %}
{% ifequal start.url "" %} <div class="label label-danger">{% trans "No link" %}</div>
<div class="label label-danger">{% trans "No link" %}</div> {% else %}
{% else %} <a href="{{ start.url }}" target="_blank" class="label label-success">{% trans "External link" %}</a>
<a href="{{ start.url }}" target="_blank" class="label label-success">{% trans "External link" %}</a> {% endifequal %}
{% endifequal %} </td>
</td> </tr>
</tr> </table>
</table> </div>
</div> </div>
</div> {% endfor %}
</div> {% else %}
{% endfor %} <h3>{% trans "There seems to be no Operations in the near future." %}</h3>
{% else %} {% endif %}
<h3>{% trans "There seems to be no Operations in the near future." %}</h3> </div>
{% endif %} <div class="col-lg-4">
</div> <div class="panel panel-default">
<div class="col-lg-3"> <div class="panel-heading">
<div class="panel panel-default"> <h2 class="panel-title">{% trans "Current Eve Time:" %}</h2>
<div class="panel-heading"> </div>
<h2 class="panel-title">{% trans "Current Eve Time:" %}</h2> <div class="panel-body">
</div> <div id="current-time"></div>
<div class="panel-body"> </div>
<div id="current-time"></div> </div>
</div> {% if timers_list %}
</div> <div class="panel panel-default">
{% if timers_list %} <div class="panel-heading">
<div class="panel panel-default"> <h2 class="panel-title">{% trans "Timers" %}</h2>
<div class="panel-heading"> </div>
<h2 class="panel-title">{% trans "Timers" %}</h2> <div class="panel-body">
</div> <table class="table table-condensed table-hover table-striped">
<div class="panel-body"> {% for notes, type in timers_list %}
<table class="table table-condensed table-hover table-striped"> <tr>
{% for notes, type in timers_list %} <td>
<tr> {{ type.solarsystem }}
<td> </td>
{{ type.solarsystem }} <td>
</td> {{ type.expires|date:"l d M H:i" }}
<td> </td>
{{ type.expires|date:"l d M H:i" }} </tr>
</td> {% endfor %}
</tr> </table>
{% endfor %} </div>
</table> </div>
</div> {% endif %}
</div> </div>
{% endif %} </div>
</div> <div id="timers" class="tab-pane fade in">
</div> <div class="col-lg-12">
<div id="timers" class="tab-pane fade in"> {% if timers_list %}
<div class="col-lg-12"> <div class="panel panel-default">
{% if timers_list %} <div class="panel-heading">
<div class="panel panel-default"> <h2 class="panel-title">{% trans "Timers" %}</h2>
<div class="panel-heading"> </div>
<h2 class="panel-title">{% trans "Timers" %}</h2> <div class="panel-body">
</div> <div class="col-lg-12">
<div class="panel-body"> <table class="table table-condensed table-hover table-striped">
<div class="col-lg-12"> <tr>
<table class="table table-condensed table-hover table-striped"> <th class="col-lg-1">{% trans "Type" %}</th>
<tr> <th class="col-lg-1">{% trans "Structure" %}</th>
<th class="col-lg-1">{% trans "Type" %}</th> <th class="col-lg-2">{% trans "Location" %}</th>
<th class="col-lg-1">{% trans "Structure" %}</th> <th class="col-lg-2">{% trans "Expires(EVE-time)" %}</th>
<th class="col-lg-2">{% trans "Location" %}</th> <th class="col-lg-1">{% trans "Owner" %}</th>
<th class="col-lg-2">{% trans "Expires(EVE-time)" %}</th> <th class="col-lg-2">{% trans "Note" %}</th>
<th class="col-lg-1">{% trans "Owner" %}</th> </tr>
<th class="col-lg-2">{% trans "Note" %}</th> {% for notes, type in timers_list %}
</tr> <tr>
{% for notes, type in timers_list %} <td>
<tr> {% ifequal type.type "Final" %}
<td> <span class="label label-danger">
{% ifequal type.type "Final" %} {{ type.type }}</span>{% else %}{{ type.type }}{% endifequal %}
<span class="label label-danger"> </td>
{{ type.type }}</span>{% else %}{{ type.type }}{% endifequal %} <td>
</td> {{ type.timer_type }}
<td> </td>
{{ type.timer_type }} <td>
</td> {{ type.solarsystem }} - Planet:{{ type.planet }} Moon:{{ type.moon }}
<td> </td>
{{ type.solarsystem }} - Planet:{{ type.planet }} Moon:{{ type.moon }} <td>
</td> {{ type.expires|date:"l d M H:i" }}
<td> </td>
{{ type.expires|date:"l d M H:i" }} <td>
</td> {{ type.owner }}
<td> </td>
{{ type.owner }} <td>
</td> {{ type.notes }}
<td> </td>
{{ type.notes }} </tr>
</td> {% endfor %}
</tr> </table>
{% endfor %} </div>
</table> </div>
</div> </div>
</div> {% else %}
</div> <h3>{% trans "There seems to be no Timers in the near future." %}</h3>
{% else %} {% endif %}
<h3>{% trans "There seems to be no Timers in the near future." %}</h3> </div>
{% endif %} </div>
</div> </div>
</div>
</div> </div>
</div>
</div> {% include 'bundles/moment-js.html' with locale=True %}
</div> <script src="{% static 'js/timers.js' %}"></script>
{% include 'bundles/moment-js.html' with locale=True %} <script type="text/javascript">
<script src="{% static 'js/timers.js' %}"></script> // Data
<script type="text/javascript"> var timers = [
// Data {% for start, op in operations_list %}
var timers = [ {
{% for start, op in operations_list %} 'id': {{ op.operation_id }},
{ 'start': moment("{{ op.start | date:"c" }}"),
'id': {{ op.operation_id }}, 'end': moment("{{ op.end | date:"c" }}"),
'start': moment("{{ op.start | date:"c" }}"), 'expired': false
'end': moment("{{ op.end | date:"c" }}"), },
'expired': false {% endfor %}
}, ]
{% endfor %} </script>
] <script type="text/javascript">
</script>
<script type="text/javascript"> timedUpdate();
setAllLocalTimes();
timedUpdate();
setAllLocalTimes(); // Start timed updates
setInterval(timedUpdate, 1000);
// Start timed updates
setInterval(timedUpdate, 1000); function timedUpdate() {
updateClock();
function timedUpdate() { updateAllTimers();
updateClock(); }
updateAllTimers();
} function updateAllTimers () {
var l = timers.length;
function updateAllTimers () { for (var i=0; i < l; ++i) {
var l = timers.length; if (timers[i].expired) continue;
for (var i=0; i < l; ++i) { updateTimer(timers[i]);
if (timers[i].expired) continue; }
updateTimer(timers[i]); }
}
} /**
* Update a timer
/** * @param timer Timer information
* Update a timer * @param timer.start Date of the timer
* @param timer Timer information * @param timer.id Id number of the timer
* @param timer.start Date of the timer * @param timer.expired
* @param timer.id Id number of the timer */
* @param timer.expired function updateTimer(timer) {
*/ if (timer.start.isAfter(Date.now())) {
function updateTimer(timer) { var duration = moment.duration(timer.start - moment(), 'milliseconds');
if (timer.start.isAfter(Date.now())) { document.getElementById("countdown" + timer.id).innerHTML = getDurationString(duration);
var duration = moment.duration(timer.start - moment(), 'milliseconds'); } else {
document.getElementById("countdown" + timer.id).innerHTML = getDurationString(duration); timer.expired = true;
} else { document.getElementById("countdown" + timer.id).innerHTML = "";
timer.expired = true; }
document.getElementById("countdown" + timer.id).innerHTML = ""; }
}
} /**
* Set all local time fields
/** */
* Set all local time fields function setAllLocalTimes() {
*/ var l = timers.length;
function setAllLocalTimes() { for (var i=0; i < l; ++i) {
var l = timers.length; setLocalTime(timers[i]);
for (var i=0; i < l; ++i) { }
setLocalTime(timers[i]); }
}
} /**
* Set the local time info for the timer
/** * @param timer Timer information
* Set the local time info for the timer * @param timer.start Date of the timer
* @param timer Timer information * @param timer.id Id number of the timer
* @param timer.start Date of the timer */
* @param timer.id Id number of the timer function setLocalTime(timer) {
*/ document.getElementById("localtime" + timer.id).innerHTML = timer.start.format("ddd @ LT");
function setLocalTime(timer) { }
document.getElementById("localtime" + timer.id).innerHTML = timer.start.format("ddd @ LT");
} function updateClock() {
document.getElementById("current-time").innerHTML = "<b>" + moment.utc().format('ddd, ll HH:mm:ss z') + "</b>";
function updateClock() { }
document.getElementById("current-time").innerHTML = "<b>" + moment.utc().format('ddd, ll HH:mm:ss z') + "</b>"; </script>
} {% endblock content %}
</script>
{% endblock content %}

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

@@ -3,6 +3,7 @@ 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
class GroupRequest(models.Model): class GroupRequest(models.Model):
@@ -23,6 +24,37 @@ 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)
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 +97,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,40 @@
{% extends "allianceauth/base.html" %}
{% load staticfiles %}
{% load i18n %}
{% block page_title %}{{ group }} {% trans "Audit Log" %}{% endblock page_title %}
{% block extra_css %}{% endblock extra_css %}
{% block content %}
<div class="col-lg-12">
<br>
{% include 'groupmanagement/menu.html' %}
<div>
{% if entries %}
<h3>{{ group }} Audit Log</h3>
<table class="table">
<tr>
<th class="text-center">{% trans "Requestor" %}</th>
<th class="text-center">{% trans "Main Character" %}</th>
<th class="text-center">{% trans "Group" %}</th>
<th class="text-center">{% trans "Type" %}</th>
<th class="text-center">{% trans "Action" %}</th>
<th class="text-center">{% trans "Actor" %}</th>
</tr>
{% for entry in entries %}
<tr>
<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>
<td class="text-center">{{ entry.action_to_str }}</td>
<td class="text-center">{{ entry.request_actor }}</td>
</tr>
{% endfor %}
</table>
{% else %}
<div class="alert alert-warning text-center">{% trans "No entries found." %}</div>
{% endif %}
</div>
</div>
{% endblock content %}

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

@@ -10,10 +10,12 @@ 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 +55,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 +67,32 @@ 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")
entries = RequestLog.objects.filter(group=group)
render_items = {'entries': entries, 'group': group.name}
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

File diff suppressed because it is too large Load Diff

View File

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

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

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

@@ -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:
@@ -214,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:
@@ -245,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

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

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

@@ -13,14 +13,14 @@
{% 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.number }} {{ 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

@@ -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,10 +68,10 @@ 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 github 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

@@ -16,12 +16,12 @@ install_requires = [
'celery>=4.0.2', 'celery>=4.0.2',
'celery_once', 'celery_once',
'django>=1.11', 'django>=1.11,<=2.0.8',
'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.7.1',
'django-celery-beat', 'django-celery-beat<=1.1.1',
'openfire-restapi', 'openfire-restapi',
'sleekxmpp', 'sleekxmpp',

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