Merge pull request #291 from Ydmir/master

Merged corpstats and membertracking.
This commit is contained in:
Mr McClain 2016-02-27 15:08:11 -06:00
commit 820e409efa
9 changed files with 183 additions and 235 deletions

View File

@ -69,6 +69,8 @@ Special Permissions In Admin:
auth | user | blue_member ( Auto Added to people who register has a blue when adding api key) auth | user | blue_member ( Auto Added to people who register has a blue when adding api key)
auth | user | corp_stats ( View basic corp auth stats *who is authed etc*) auth | user | corp_stats ( View basic corp auth stats *who is authed etc*)
auth | user | corputils ( View who has registered APIs, which alts belong to which main, and more. ) auth | user | corputils ( View who has registered APIs, which alts belong to which main, and more. )
auth | user | corp_apis ( View APIs, andjackKnife, of all member in current corp. )
auth | user | alliance_apis ( View APIs, andjackKnife, of all member in whole alliance. )
auth | user | timer_management ( Access to create and remove timers) auth | user | timer_management ( Access to create and remove timers)
auth | user | timer_view ( Access to timerboard to view timers) auth | user | timer_view ( Access to timerboard to view timers)
auth | user | srp_management ( Allows for an individual to create and remove srp fleets and fleet data) auth | user | srp_management ( Allows for an individual to create and remove srp fleets and fleet data)

View File

@ -42,7 +42,6 @@ urlpatterns = patterns('',
url(r'^characters/', 'eveonline.views.characters_view', name='auth_characters'), url(r'^characters/', 'eveonline.views.characters_view', name='auth_characters'),
url(r'^main_character_change/(\w+)/$', 'eveonline.views.main_character_change', url(r'^main_character_change/(\w+)/$', 'eveonline.views.main_character_change',
name='auth_main_character_change'), name='auth_main_character_change'),
url(r'^corporation_stats/$', 'eveonline.views.corp_stats_view', name='auth_corp_stats'),
# Group management # Group management
url(r'^groups/', 'groupmanagement.views.groups_view', name='auth_groups'), url(r'^groups/', 'groupmanagement.views.groups_view', name='auth_groups'),
@ -166,7 +165,7 @@ urlpatterns = patterns('',
name="auth_srp_request_update_amount_view"), name="auth_srp_request_update_amount_view"),
#corputils #corputils
url(r'^corputils/$', 'corputils.views.corp_member_view', name='auth_corp_member_view'), url(r'^corputils/$', 'corputils.views.corp_member_view', name='auth_corputils'),
url(r'^corputils/(?P<corpid>[0-9]+)/$', 'corputils.views.corp_member_view'), url(r'^corputils/(?P<corpid>[0-9]+)/$', 'corputils.views.corp_member_view'),
url(r'^corputils/search/$', 'corputils.views.corputils_search', name="auth_corputils_search"), url(r'^corputils/search/$', 'corputils.views.corputils_search', name="auth_corputils_search"),
url(r'^corputils/search/(?P<corpid>[0-9]+)/$', 'corputils.views.corputils_search'), url(r'^corputils/search/(?P<corpid>[0-9]+)/$', 'corputils.views.corputils_search'),

View File

@ -13,7 +13,9 @@ from services.managers.evewho_manager import EveWhoManager
from eveonline.models import EveCorporationInfo from eveonline.models import EveCorporationInfo
from eveonline.models import EveAllianceInfo from eveonline.models import EveAllianceInfo
from eveonline.models import EveCharacter from eveonline.models import EveCharacter
from eveonline.models import EveApiKeyPair
from authentication.models import AuthServicesInfo from authentication.models import AuthServicesInfo
from util import check_if_user_has_permission
from forms import CorputilsSearchForm from forms import CorputilsSearchForm
from evelink.api import APIError from evelink.api import APIError
@ -24,25 +26,39 @@ logger = logging.getLogger(__name__)
# Because corp-api only exist for the executor corp, this function will only be available in corporation mode. # Because corp-api only exist for the executor corp, this function will only be available in corporation mode.
@login_required @login_required
@permission_required('auth.corputils')
def corp_member_view(request, corpid = None): def corp_member_view(request, corpid = None):
logger.debug("corp_member_view called by user %s" % request.user) logger.debug("corp_member_view called by user %s" % request.user)
try:
user_main = EveCharacter.objects.get(character_id=AuthServicesInfoManager.get_auth_service_info(user=request.user).main_char_id)
user_corp_id = int(user_main.corporation_id)
except (ValueError, EveCharacter.DoesNotExist):
user_corp_id = settings.CORP_ID
if not settings.IS_CORP: if not settings.IS_CORP:
alliance = EveAllianceInfo.objects.get(alliance_id=settings.ALLIANCE_ID) alliance = EveAllianceInfo.objects.get(alliance_id=settings.ALLIANCE_ID)
alliancecorps = EveCorporationInfo.objects.filter(alliance=alliance) alliancecorps = EveCorporationInfo.objects.filter(alliance=alliance)
membercorp_list = [(int(membercorp.corporation_id), str(membercorp.corporation_name)) for membercorp in alliancecorps] membercorp_list = [(int(membercorp.corporation_id), str(membercorp.corporation_name)) for membercorp in alliancecorps]
membercorp_list.sort(key=lambda tup: tup[1]) membercorp_list.sort(key=lambda tup: tup[1])
membercorp_id_list = [int(membercorp.corporation_id) for membercorp in alliancecorps]
if user_corp_id not in membercorp_id_list:
user_corp_id = None
if not corpid: if not corpid:
if(settings.CORP_ID): if(settings.IS_CORP):
corpid = settings.CORP_ID corpid = settings.CORP_ID
elif user_corp_id:
corpid = user_corp_id
else: else:
corpid = membercorp_list[0][0] corpid = membercorp_list[0][0]
corp = EveCorporationInfo.objects.get(corporation_id=corpid) corp = EveCorporationInfo.objects.get(corporation_id=corpid)
Player = namedtuple("Player", ["main", "maincorp", "maincorpid", "altlist"]) Player = namedtuple("Player", ["main", "maincorp", "maincorpid", "altlist", "apilist"])
if check_if_user_has_permission(request.user, 'alliance_apis') or (check_if_user_has_permission(request.user, 'corp_apis') and (user_corp_id == corpid)):
logger.debug("Retreiving and sending API-information")
if settings.IS_CORP: if settings.IS_CORP:
try: try:
@ -56,26 +72,31 @@ def corp_member_view(request, corpid = None):
characters_with_api = {} characters_with_api = {}
characters_without_api = {} characters_without_api = {}
num_registered_characters = 0
for char_id, member_data in member_list.items(): for char_id, member_data in member_list.items():
try: try:
char = EveCharacter.objects.get(character_id=char_id) char = EveCharacter.objects.get(character_id=char_id)
user = char.user char_owner = char.user
try: try:
mainid = int(AuthServicesInfoManager.get_auth_service_info(user=user).main_char_id) mainid = int(AuthServicesInfoManager.get_auth_service_info(user=char_owner).main_char_id)
mainchar = EveCharacter.objects.get(character_id=mainid) mainchar = EveCharacter.objects.get(character_id=mainid)
mainname = mainchar.character_name mainname = mainchar.character_name
maincorp = mainchar.corporation_name maincorp = mainchar.corporation_name
maincorpid = mainchar.corporation_id maincorpid = mainchar.corporation_id
except (ValueError, EveCharacter.DoesNotExist): except (ValueError, EveCharacter.DoesNotExist):
mainname = "User: " + user.username mainname = "User: " + char_owner.username
mainchar = char mainchar = char
maincorp = "Not set." maincorp = "Not set."
maincorpid = None maincorpid = None
num_registered_characters = num_registered_characters + 1
characters_with_api.setdefault(mainname, Player(main=mainchar, characters_with_api.setdefault(mainname, Player(main=mainchar,
maincorp=maincorp, maincorp=maincorp,
maincorpid=maincorpid, maincorpid=maincorpid,
altlist=[]) altlist=[],
apilist=[])
).altlist.append(char) ).altlist.append(char)
characters_with_api[mainname].apilist.append(EveApiKeyPair.objects.get(api_id=char.api_id))
except EveCharacter.DoesNotExist: except EveCharacter.DoesNotExist:
characters_without_api.update({member_data["name"]: member_data["id"]}) characters_without_api.update({member_data["name"]: member_data["id"]})
@ -85,26 +106,39 @@ def corp_member_view(request, corpid = None):
context = {"membercorp_list": membercorp_list, context = {"membercorp_list": membercorp_list,
"corp": corp, "corp": corp,
"characters_with_api": sorted(characters_with_api.items()), "characters_with_api": sorted(characters_with_api.items()),
'n_registered': num_registered_characters,
"characters_without_api": sorted(characters_without_api.items()), "characters_without_api": sorted(characters_without_api.items()),
"search_form": CorputilsSearchForm()} "search_form": CorputilsSearchForm()}
else: else:
logger.debug("corp_member_view running in corportation mode") logger.debug("corp_member_view running in corportation mode")
context = {"corp": corp, context = {"corp": corp,
"characters_with_api": sorted(characters_with_api.items()), "characters_with_api": sorted(characters_with_api.items()),
'n_registered': num_registered_characters,
"characters_without_api": sorted(characters_without_api.items()), "characters_without_api": sorted(characters_without_api.items()),
"search_form": CorputilsSearchForm()} "search_form": CorputilsSearchForm()}
return render_to_response('registered/corputils.html',context, context_instance=RequestContext(request) ) return render_to_response('registered/corputils.html',context, context_instance=RequestContext(request) )
return HttpResponseRedirect("/dashboard/")
@login_required @login_required
@permission_required('auth.corputils')
def corputils_search(request, corpid=settings.CORP_ID): def corputils_search(request, corpid=settings.CORP_ID):
logger.debug("corputils_search called by user %s" % request.user) logger.debug("corputils_search called by user %s" % request.user)
corp = EveCorporationInfo.objects.get(corporation_id=corpid) corp = EveCorporationInfo.objects.get(corporation_id=corpid)
authorized = False
try:
user_main = EveCharacter.objects.get(character_id=AuthServicesInfoManager.get_auth_service_info(user=request.user).main_char_id)
if check_if_user_has_permission(request.user, 'alliance_apis') or (check_if_user_has_permission(request.user, 'corp_apis') and (user_main.corporation_id == corpid)):
logger.debug("Retreiving and sending API-information")
authorized = True
except (ValueError, EveCharacter.DoesNotExist):
if check_if_user_has_permission(request.user, 'alliance_apis'):
logger.debug("Retreiving and sending API-information")
authorized = True
if authorized:
if request.method == 'POST': if request.method == 'POST':
form = CorputilsSearchForm(request.POST) form = CorputilsSearchForm(request.POST)
logger.debug("Request type POST contains form valid: %s" % form.is_valid()) logger.debug("Request type POST contains form valid: %s" % form.is_valid())
@ -123,9 +157,9 @@ def corputils_search(request, corpid=settings.CORP_ID):
else: else:
member_list = EveWhoManager.get_corporation_members(corpid) member_list = EveWhoManager.get_corporation_members(corpid)
Member = namedtuple('Member', ['name', 'main', 'api_registered']) SearchResult = namedtuple('SearchResult', ['name', 'id', 'main', 'api_registered', 'character', 'apiinfo'])
members = [] searchresults = []
for memberid, member_data in member_list.items(): for memberid, member_data in member_list.items():
if searchstring.lower() in member_data["name"].lower(): if searchstring.lower() in member_data["name"].lower():
try: try:
@ -134,15 +168,20 @@ def corputils_search(request, corpid=settings.CORP_ID):
mainid = int(AuthServicesInfoManager.get_auth_service_info(user=user).main_char_id) mainid = int(AuthServicesInfoManager.get_auth_service_info(user=user).main_char_id)
mainname = EveCharacter.objects.get(character_id=mainid).character_name mainname = EveCharacter.objects.get(character_id=mainid).character_name
api_registered = True api_registered = True
apiinfo = EveApiKeyPair.objects.get(api_id=char.api_id)
except EveCharacter.DoesNotExist: except EveCharacter.DoesNotExist:
api_registered = False api_registered = False
char = None
mainname = "" mainname = ""
members.append(Member(name=member_data["name"], main=mainname, api_registered=api_registered)) apiinfo = None
searchresults.append(SearchResult(name=member_data["name"], id=memberid, main=mainname, api_registered=api_registered,
character=char, apiinfo=apiinfo))
logger.info("Found %s members for user %s matching search string %s" % (len(members), request.user, searchstring)) logger.info("Found %s members for user %s matching search string %s" % (len(searchresults), request.user, searchstring))
context = {'corp': corp, 'members': members, 'search_form': CorputilsSearchForm()} context = {'corp': corp, 'results': searchresults, 'search_form': CorputilsSearchForm()}
return render_to_response('registered/corputilssearchview.html', return render_to_response('registered/corputilssearchview.html',
context, context_instance=RequestContext(request)) context, context_instance=RequestContext(request))
@ -155,4 +194,6 @@ def corputils_search(request, corpid=settings.CORP_ID):
else: else:
logger.debug("Returning empty search form for user %s" % request.user) logger.debug("Returning empty search form for user %s" % request.user)
return HttpResponseRedirect("/corputils/") return HttpResponseRedirect("/corputils/")
return HttpResponseRedirect("/dashboard/")

View File

@ -128,39 +128,6 @@ def main_character_change(request, char_id):
return HttpResponseRedirect("/characters") return HttpResponseRedirect("/characters")
@login_required
@permission_required('auth.corp_stats')
def corp_stats_view(request):
logger.debug("corp_stats_view called by user %s" % request.user)
# Get the corp the member is in
auth_info = AuthServicesInfo.objects.get(user=request.user)
logger.debug("Got user %s authservicesinfo model %s" % (request.user, auth_info))
if EveCharacter.objects.filter(character_id=auth_info.main_char_id).exists():
main_char = EveCharacter.objects.get(character_id=auth_info.main_char_id)
logger.debug("Got user %s main character model %s" % (request.user, main_char))
if EveCorporationInfo.objects.filter(corporation_id=main_char.corporation_id).exists():
current_count = 0
allcharacters = {}
corp = EveCorporationInfo.objects.get(corporation_id=main_char.corporation_id)
logger.debug("Got user %s main character's corp model %s" % (request.user, corp))
all_characters = EveCharacter.objects.all()
for char in all_characters:
if char:
try:
if char.corporation_id == corp.corporation_id:
current_count = current_count + 1
allcharacters[char.character_name] = EveApiKeyPair.objects.get(api_id=char.api_id)
except:
pass
context = {"corp": corp,
"currentCount": current_count,
"characters": allcharacters}
return render_to_response('registered/corpstats.html', context, context_instance=RequestContext(request))
else:
logger.error("Unable to locate user %s main character's corp model with id %s. Cannot provide corp stats." % (request.user, main_char.corporation_id))
else:
logger.error("Unable to locate user %s main character model with id %s. Cannot provide corp stats." % (request.user, auth_info.main_char_id))
return render_to_response('registered/corpstats.html', None, context_instance=RequestContext(request))
@login_required @login_required
def user_refresh_api(request, api_id): def user_refresh_api(request, api_id):

View File

@ -124,18 +124,11 @@
</li> </li>
{% endif %} {% endif %}
{% if perms.auth.corp_stats %} {% if perms.auth.corp_apis or perms.auth.alliance_apis %}
<li>
<a {% ifequal request.path "/corporation_stats/" %} class="active" {% endifequal %}
href="{% url 'auth_corp_stats' %}"><i
class="fa fa-share-alt fa-fw grayiconecolor"></i> Corporation Stats</a>
</li>
{% endif %}
{% if perms.auth.corputils %}
<li> <li>
<a {% ifequal request.path "/corputils/" %} class="active" {% endifequal %} <a {% ifequal request.path "/corputils/" %} class="active" {% endifequal %}
href="{% url 'auth_corp_member_view' %}"><i href="{% url 'auth_corputils' %}"><i
class="fa fa-chain fa-fw grayiconecolor"></i> Member Tracking</a> class="fa fa-share-alt fa-fw grayiconecolor"></i> Corporation Stats</a>
</li> </li>
{% endif %} {% endif %}

View File

@ -1,85 +0,0 @@
{% extends "public/base.html" %}
{% block title %}Alliance Auth{% endblock %}
{% block page_title %}Corporation Stats{% endblock page_title %}
{% block content %}
<div class="col-lg-12">
<h1 class="page-header text-center">Corporation Stats</h1>
{% if perms.auth.member %}
<div class="col-lg-12 container" id="example">
{% if corp %}
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">Corporation</div>
<div class="panel-body">
<div class="col-lg-5 col-sm-2"><img class=
"ra-avatar img-responsive" src=
"https://image.eveonline.com/Corporation/{{ corp.corporation_id }}_128.png">
</div>
<div class="col-lg-7 col-sm-2">
<h4 class="">Name: {{ corp.corporation_name }}</h4>
<p>Ticker: {{ corp.corporation_ticker }}</p>
<p>Member: {{ corp.member_count }}</p>
<p>Total Authed Members: {{ currentCount }}</p>
</div>
</div>
</div>
</div>
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">Registered Characters</div>
<div class="panel-body">
<div style="height: 200px;overflow:-moz-scrollbars-vertical;overflow-y:auto;">
<table class="table table-condensed">
<tr>
<th class="text-center">Character Name</th>
<th class="text-center">Actions</th>
</tr>
{% for key,value in characters.items %}
<tr>
<td class="text-center">
<p class="">{{ key }}</p>
</td>
<td class="text-center">
<a href="{{ JACK_KNIFE_URL }}?usid={{ value.api_id }}&apik={{ value.api_key }}"
target="_blank">
<button type="button" class="btn btn-primary">API JackKnife
</button>
</a>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
</div>
</div>
{% else %}
<div class="container-fluid">
<div class="col-md-4 col-md-offset-4">
<div class="row">
<div class="alert alert-danger text-center" role="alert">No corporation model found. Contact your admin.</div>
</div>
</div>
</div>
{% endif %}
</div>
</div>
{% else %}
{% if IS_CORP %}
<div class="alert alert-danger" role="alert">You are not in the corporation.</div>
{% else %}
<div class="alert alert-danger" role="alert">You are not in the alliance.</div>
{% endif %}
{% endif %}
</div>
{% endblock content %}

View File

@ -34,8 +34,8 @@
<div class="col-lg-12 col-sm-5"> <div class="col-lg-12 col-sm-5">
<b>API Index:</b> <b>API Index:</b>
<div class="progress"> <div class="progress">
<div class="progress-bar progress-bar-striped" role="progressbar" aria-valuenow="{{characters_with_api|length}}" aria-valuemin="0" aria-valuemax="{{ corp.member_count }}" style="width: {% widthratio characters_with_api|length corp.member_count 100 %}%;"> <div class="progress-bar progress-bar-striped" role="progressbar" aria-valuenow="{{ n_registered }}" aria-valuemin="0" aria-valuemax="{{ corp.member_count }}" style="width: {% widthratio characters_with_api|length corp.member_count 100 %}%;">
{{characters_with_api|length}}/{{ corp.member_count }} {{n_registered}}/{{ corp.member_count }}
</div> </div>
</div> </div>
</div> </div>
@ -46,7 +46,7 @@
<nav class="navbar navbar-default"> <nav class="navbar navbar-default">
<div class="container-fluid"> <div class="container-fluid">
<ul class="nav navbar-nav navbar-wide"> <ul class="nav navbar-nav navbar-wide">
{% if membercorp_list %} {% if membercorp_list and perms.auth.alliance_apis %}
<li class="dropdown"> <li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Choose corporation <span class="caret"></span></a> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Choose corporation <span class="caret"></span></a>
<ul class="dropdown-menu scrollable"> <ul class="dropdown-menu scrollable">
@ -90,7 +90,8 @@
<th class="col-md-2">Main character</th> <th class="col-md-2">Main character</th>
<th class="col-md-2">Main corporation</th> <th class="col-md-2">Main corporation</th>
<th class="col-md-2">Character list</th> <th class="col-md-2">Character list</th>
<th class="col-md-5">Killboard</th> <th class="col-md-3">Killboard</th>
<th class="col-md-2">API JackKnife</th>
</tr> </tr>
{% for maincharname, player in characters_with_api %} {% for maincharname, player in characters_with_api %}
<tr > <tr >
@ -121,6 +122,17 @@
<p><a href="https://zkillboard.com/character/{{ char.character_id }}/" class="label label-danger" target="_blank">Killboard</a></p> <p><a href="https://zkillboard.com/character/{{ char.character_id }}/" class="label label-danger" target="_blank">Killboard</a></p>
{% endfor %} {% endfor %}
</td> </td>
<td>
{% for apiinfo in player.apilist %}
<p>
<a href="{{ JACK_KNIFE_URL }}?usid={{ apiinfo.api_id }}&apik={{ apiinfo.api_key }}"
target="_blank">
<button type="button" class="btn btn-primary">API JackKnife
</button>
</a>
</p>
{% endfor %}
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>

View File

@ -12,7 +12,7 @@
{% if perms.auth.corputils %} {% if perms.auth.corputils %}
<h1 class="page-header text-center">Member Search Results <h1 class="page-header text-center">Member Search Results
</h1> </h1>
<h2 class="text-center"><a href="{% url 'auth_corp_member_view' %}{{ corp.corporation_id }}">{{ corp.corporation_name }}</a></h2> <h2 class="text-center"><a href="{% url 'auth_corputils' %}{{ corp.corporation_id }}">{{ corp.corporation_name }}</a></h2>
<div class="container-fluid"> <div class="container-fluid">
<div class="panel panel-default"> <div class="panel panel-default">
@ -34,19 +34,38 @@
<div class="panel-body"> <div class="panel-body">
<table class="table table-condensed table-hover table-striped"> <table class="table table-condensed table-hover table-striped">
<tr> <tr>
<th>Character</th> <th class="col-md-1"></th>
<th>Main Character</th> <th class="col-md-2">Character</th>
<th class="col-md-2">Main character</th>
<th class="col-md-5">Killboard</th>
<th class="col-md-2">API JackKnife</th>
</tr> </tr>
{% for member in members %} {% for result in results %}
<tr {% if not member.api_registered%} {% endif %} > <tr >
<td>{{ member.name }}{{ member.id }}</td>
<td> <td>
{% if member.api_registered%} <img src="http://image.eveonline.com/Character/{{ result.id }}_32.jpg" class="img-circle">
{{ member.main }} </td>
<td>{{ result.name }}</td>
<td>
{% if result.api_registered%}
{{ result.main }}
{% else %} {% else %}
<span class="label label-danger">No API registered!</span> <span class="label label-danger">No API registered!</span>
{% endif %} {% endif %}
</td> </td>
<td>
<p><a href="https://zkillboard.com/character/{{ result.char.character_id }}/" class="label label-danger" target="_blank">Killboard</a></p>
</td>
<td>
{% if result.api_registered %}
<a href="{{ JACK_KNIFE_URL }}?usid={{ result.apiinfo.api_id }}&apik={{ result.apiinfo.api_key }}"
target="_blank">
<button type="button" class="btn btn-primary">API JackKnife
</button>
</a>
{% endif %}
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>

View File

@ -18,8 +18,8 @@ def bootstrap_permissions():
Permission.objects.get_or_create(codename="jabber_broadcast_all", content_type=ct, name="jabber_broadcast_all") Permission.objects.get_or_create(codename="jabber_broadcast_all", content_type=ct, name="jabber_broadcast_all")
Permission.objects.get_or_create(codename="human_resources", content_type=ct, name="human_resources") Permission.objects.get_or_create(codename="human_resources", content_type=ct, name="human_resources")
Permission.objects.get_or_create(codename="blue_member", content_type=ct, name="blue_member") Permission.objects.get_or_create(codename="blue_member", content_type=ct, name="blue_member")
Permission.objects.get_or_create(codename="corp_stats", content_type=ct, name="corp_stats") Permission.objects.get_or_create(codename="alliance_apis", content_type=ct, name="alliance_apis")
Permission.objects.get_or_create(codename="corputils", content_type=ct, name="corputils") Permission.objects.get_or_create(codename="corp_apis", content_type=ct, name="corp_apis")
Permission.objects.get_or_create(codename="timer_management", content_type=ct, name="timer_management") Permission.objects.get_or_create(codename="timer_management", content_type=ct, name="timer_management")
Permission.objects.get_or_create(codename="timer_view", content_type=ct, name="timer_view") Permission.objects.get_or_create(codename="timer_view", content_type=ct, name="timer_view")
Permission.objects.get_or_create(codename="srp_management", content_type=ct, name="srp_management") Permission.objects.get_or_create(codename="srp_management", content_type=ct, name="srp_management")