# Eve W-Space
# Copyright (C) 2013 Andrew Austin and other contributors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. An additional term under section
# 7 of the GPL is included in the LICENSE file.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.db import models
from core.models import Type, Location
from API.models import CorpAPIKey
from core.models import Corporation, Alliance
from Map.models import System
import csv
from django.contrib.auth import get_user_model
import pytz
User = get_user_model()
[docs]class POS(models.Model):
"""Represents a POS somewhere in space."""
system = models.ForeignKey(System, related_name="poses")
planet = models.IntegerField()
moon = models.IntegerField()
towertype = models.ForeignKey(Type, related_name="inspace")
corporation = models.ForeignKey(Corporation, related_name="poses")
posname = models.CharField(max_length=100, blank=True, null=True)
fitting = models.TextField(blank=True, null=True)
#Using CCP's status codes here for sanity with API checks
status = models.IntegerField(choices = ((0, 'Unanchored'), (1, 'Anchored'),
(2, 'Onlining'), (3, 'Reinforced'), (4, 'Online')))
#This should be the time the tower exits RF
#TODO: add a validator to make sure this is only set if status = 3 (Reinforced)
rftime = models.DateTimeField(null=True, blank=True)
updated = models.DateTimeField()
# These values will be set by the TSV parser from d-scan data if available
guns = models.IntegerField(null=True, blank=True)
ewar = models.IntegerField(null=True, blank=True)
sma = models.IntegerField(null=True, blank=True)
hardener = models.IntegerField(null=True, blank=True)
# This is a short comment that is displayed as a warning
warpin_notice = models.CharField(blank=True, null=True, max_length=64)
class Meta:
ordering = ['system__name', 'planet', 'moon']
def clean(self):
from django.core.exceptions import ValidationError
if self.rftime and self.status != 3:
raise ValidationError("A POS cannot have an rftime unless it is reinforced")
def __unicode__(self):
return self.posname
#overide save to implement posname defaulting to towertype.name
def save(self, *args, **kwargs):
if not self.posname:
self.posname = self.towertype.name
# Mark tower as having been updated
from datetime import datetime
import pytz
self.updated = datetime.now(pytz.utc)
super(POS, self).save(*args, **kwargs)
[docs] def size(self):
"""
Returns the size of the tower, Small Medium or Large.
"""
if u'Small' in self.towertype.name:
return u'Small'
if u'Medium' in self.towertype.name:
return u'Medium'
return u'Large'
[docs] def fit_from_dscan(self, dscan):
"""
Fills in a POS's fitting from a copy / paste of d-scan results.
"""
return self.fit_from_iterable(csv.reader(dscan.splitlines(), delimiter="\t"))
[docs] def fit_from_iterable(self, fit):
"""
Fills in a POS's fitting from an iterable (normally parsed d-scan)
"""
from core.models import Type
itemDict={}
# marketGroupIDs to consider guns, ewar, hardeners, and smas
gunsGroups = [480, 479, 594, 595, 596]
ewarGroups = [481, 1009]
smaGroups = [484,]
hardenerGroups = [485,]
towers = 0
self.sma = 0
self.hardener = 0
self.guns = 0
self.ewar = 0
for row in fit:
try:
itemType = Type.objects.get(name=row[1])
except Type.DoesNotExist: #odd bug where invalid items get into dscan
continue
if itemType.marketgroup:
groupTree = []
parent = itemType.marketgroup
while parent:
groupTree.append(parent.id)
parent = parent.parentgroup
if itemType.marketgroup.id in gunsGroups:
self.guns += 1
if itemType.marketgroup.id in ewarGroups:
self.ewar += 1
if itemType.marketgroup.id in smaGroups:
self.sma += 1
if itemType.marketgroup.id in hardenerGroups:
self.hardener += 1
if itemType.marketgroup.id == 478:
towers += 1
towertype = itemType
posname = row[0]
if itemDict.has_key(itemType.name):
itemDict[itemType.name] += 1
elif 1285 in groupTree and 478 not in groupTree:
itemDict.update({itemType.name: 1})
self.fitting = "Imported from D-Scan:\n"
for itemtype in itemDict:
self.fitting += "\n%s : %s" % (itemtype, itemDict[itemtype])
if towers == 1 and self.towertype_id is None and self.posname is None:
self.towertype = towertype
self.posname = posname
if towers == 0 and self.towertype_id is None:
raise AttributeError('No POS in the D-Scan!')
elif towers <= 1:
self.save()
else:
raise AttributeError('Too many towers detected in the D-Scan!')
[docs]class CorpPOS(POS):
"""A corp-controlled POS with manager and password data."""
manager = models.ForeignKey(User, null=True, blank=True, related_name='poses')
password = models.CharField(max_length=100)
description = models.TextField(null=True, blank=True)
#Let's store the CCP Item ID for the tower here to make API lookup easier
#If it is null, then we are not tracking this POS via API
apiitemid = models.BigIntegerField(null=True, blank=True)
apikey = models.ForeignKey(CorpAPIKey, null=True, blank=True, related_name='poses')
class Meta:
permissions = (('can_see_pos_pw', 'Can see corp POS passwords.'),
('can_see_all_pos', 'Sees all corp POSes regardless of manager.'),)
[docs]class POSApplication(models.Model):
"""Represents an application for a personal POS."""
applicant = models.ForeignKey(User, null=True, blank=True, related_name='posapps')
towertype = models.ForeignKey(Type, null=True, blank=True, related_name='posapps')
residents = models.ManyToManyField(User)
normalfit = models.TextField()
siegefit = models.TextField()
#Once it is approved, we will fill in these two to tie the records together
approved = models.DateTimeField(blank=True, null=True)
posrecord = models.ForeignKey(CorpPOS, blank=True, null=True, related_name='application')
class Meta:
permissions = (('can_close_pos_app', 'Can dispose of corp POS applications.'),)
def __unicode__(self):
return 'Applicant: %s Tower: %s' % (self.applicant.username, self.towertype.name)
[docs]class POSVote(models.Model):
"""Represents a vote on a personal POS application."""
application = models.ForeignKey(POSApplication, related_name='votes')
voter = models.ForeignKey(User, related_name='posvotes')
vote = models.IntegerField(choices=((0,'Deny'), (1, 'Approve'), (2, 'Abstain')))