mirror of
https://github.com/nikdoof/posmaster.git
synced 2025-12-11 12:42:15 +00:00
Initial import of the codebase
This commit is contained in:
4
README.md
Normal file
4
README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
posmaster
|
||||
=========
|
||||
|
||||
EVE Online POS Management System
|
||||
9
posmaster/manage.py
Executable file
9
posmaster/manage.py
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "posmaster.settings")
|
||||
from django.core.management import execute_from_command_line
|
||||
execute_from_command_line(sys.argv)
|
||||
5
posmaster/poscore/__init__.py
Normal file
5
posmaster/poscore/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
try:
|
||||
VERSION = __import__('pkg_resources') \
|
||||
.get_distribution(__name__).version
|
||||
except Exception, e:
|
||||
VERSION = 'unknown'
|
||||
40
posmaster/poscore/admin.py
Normal file
40
posmaster/poscore/admin.py
Normal file
@@ -0,0 +1,40 @@
|
||||
from django.contrib import admin
|
||||
from poscore.models.objects import Tower, InSpaceObject, Fuel
|
||||
from poscore.models.api import APIKey
|
||||
|
||||
class APIKeyAdmin(admin.ModelAdmin):
|
||||
list_display = ['keyid', 'vcode', 'active']
|
||||
admin.site.register(APIKey, APIKeyAdmin)
|
||||
|
||||
class FuelInlineAdmin(admin.TabularInline):
|
||||
model = Fuel
|
||||
list_display = ['resource', 'level', 'updated_datetime']
|
||||
|
||||
def has_add_permission(self, request):
|
||||
return False
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
return False
|
||||
|
||||
class TowerAdmin(admin.ModelAdmin):
|
||||
list_display = ['id', 'name', 'state']
|
||||
list_filter = ['state']
|
||||
readonly_fields = ['id', 'type', 'owner', 'system', 'x', 'y', 'z', 'state', 'moon']
|
||||
|
||||
inlines = [
|
||||
FuelInlineAdmin,
|
||||
]
|
||||
|
||||
def has_add_permission(self, request):
|
||||
return False
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
return False
|
||||
|
||||
admin.site.register(Tower, TowerAdmin)
|
||||
|
||||
class InSpaceObjectAdmin(admin.ModelAdmin):
|
||||
list_display = ['pk', 'type', 'system']
|
||||
list_filter = ['type__name']
|
||||
|
||||
admin.site.register(InSpaceObject, InSpaceObjectAdmin)
|
||||
14
posmaster/poscore/app_defines.py
Normal file
14
posmaster/poscore/app_defines.py
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
# Distance units, in meters (EVE Units, aka heavily rounded)
|
||||
DISTANCE_METER = 1
|
||||
DISTANCE_KILOMETER = 1000
|
||||
DISTANCE_ASTRONOMICAL_UNIT = 149598000000
|
||||
DISTANCE_LIGHT_YEAR = 9460000000000000
|
||||
|
||||
# Important Type Groups we need to filter on
|
||||
|
||||
TYPEGROUP_TOWERS = [365]
|
||||
TYPEGROUP_FUEL = [1136, 423]
|
||||
|
||||
# Important attributes types
|
||||
ATTRIBUTE_MAX_STRUCTURE_DISTANCE = 650
|
||||
1
posmaster/poscore/fixtures/inferno11.json
Normal file
1
posmaster/poscore/fixtures/inferno11.json
Normal file
File diff suppressed because one or more lines are too long
0
posmaster/poscore/management/__init__.py
Normal file
0
posmaster/poscore/management/__init__.py
Normal file
0
posmaster/poscore/management/commands/__init__.py
Normal file
0
posmaster/poscore/management/commands/__init__.py
Normal file
23
posmaster/poscore/management/commands/import_alliances.py
Normal file
23
posmaster/poscore/management/commands/import_alliances.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.db import transaction
|
||||
from poscore.models import Alliance, Corporation
|
||||
from eveapi import EVEAPIConnection
|
||||
|
||||
class Command(BaseCommand):
|
||||
args = ''
|
||||
help = 'Updates alliances from the EVE API'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
api = EVEAPIConnection()
|
||||
|
||||
alliance_list = api.eve.AllianceList().alliances
|
||||
print 'Updating %d alliances... ' % len(alliance_list)
|
||||
with transaction.commit_on_success():
|
||||
for alliance in alliance_list:
|
||||
allobj, created = Alliance.objects.get_or_create(pk=alliance.allianceID)
|
||||
allobj.name = alliance.name
|
||||
allobj.save()
|
||||
corp_ids = [x.corporationID for x in alliance.memberCorporations]
|
||||
Corporation.objects.exclude(pk__in=corp_ids).update(alliance=None)
|
||||
Corporation.objects.filter(pk__in=corp_ids).update(alliance=allobj)
|
||||
print 'Done'
|
||||
79
posmaster/poscore/management/commands/import_assets.py
Normal file
79
posmaster/poscore/management/commands/import_assets.py
Normal file
@@ -0,0 +1,79 @@
|
||||
from datetime import datetime
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.utils.timezone import utc, now
|
||||
from poscore.models import APIKey, Location, System, Moon, Tower, Corporation, InSpaceObject
|
||||
from eveapi import EVEAPIConnection
|
||||
|
||||
class Command(BaseCommand):
|
||||
args = ''
|
||||
help = 'Updates the in-space assets from the EVE API'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
api = EVEAPIConnection()
|
||||
|
||||
for key in APIKey.objects.filter(active=True):
|
||||
auth = key.auth(api)
|
||||
|
||||
assets = auth.corp.AssetList().assets
|
||||
for asset in assets:
|
||||
if int(asset.flag) > 0:
|
||||
continue
|
||||
|
||||
try:
|
||||
obj = InSpaceObject.objects.get(pk=asset.itemID)
|
||||
except InSpaceObject.DoesNotExist:
|
||||
obj = InSpaceObject(pk=asset.itemID, type_id=asset.typeID, system_id=asset.locationID)
|
||||
obj.save()
|
||||
|
||||
print "Importing POSes"
|
||||
starbases = auth.corp.StarbaseList().starbases
|
||||
for base in starbases:
|
||||
owner, created = Corporation.objects.get_or_create(pk=base.standingOwnerID)
|
||||
system, created = System.objects.get_or_create(pk=base.locationID)
|
||||
moon, created = Moon.objects.get_or_create(pk=base.moonID)
|
||||
|
||||
try:
|
||||
twr = Tower.objects.get(pk=base.itemID)
|
||||
except Tower.DoesNotExist:
|
||||
twr = Tower(pk=base.itemID, type_id=base.typeID, system_id=base.locationID, moon_id=base.moonID, name="Tower %s" % base.itemID, owner=owner)
|
||||
twr.state = base.state
|
||||
twr.state_datetime = datetime.fromtimestamp(base.stateTimestamp, utc)
|
||||
twr.online_datetime = datetime.fromtimestamp(base.onlineTimestamp, utc)
|
||||
twr.save()
|
||||
|
||||
print "Flagging POSes missing from the API"
|
||||
tower_ids = [x.itemID for x in starbases]
|
||||
Tower.objects.exclude(pk__in=tower_ids).update(state=Tower.STATE_MISSING)
|
||||
print "Done"
|
||||
|
||||
# Grab locations
|
||||
twr_dict = {}
|
||||
for twr in InSpaceObject.objects.filter(x=None):
|
||||
twr_dict[twr.pk] = twr
|
||||
keys = twr_dict.keys()
|
||||
|
||||
while len(keys) > 0:
|
||||
if len(keys) < 250:
|
||||
call = keys
|
||||
keys = []
|
||||
else:
|
||||
call = keys[:250]
|
||||
keys = keys[251:]
|
||||
|
||||
id_list = ','.join([str(x) for x in call])
|
||||
print "Updating %d locations" % len(call)
|
||||
locations = auth.corp.Locations(IDs=id_list).locations
|
||||
for loc in locations:
|
||||
twr = twr_dict.get(int(loc.itemID), None)
|
||||
if not twr:
|
||||
continue
|
||||
twr.name = loc.itemName
|
||||
twr.x = loc.x
|
||||
twr.y = loc.y
|
||||
twr.z = loc.z
|
||||
twr.save()
|
||||
|
||||
|
||||
|
||||
self.stdout.write('Done\n')
|
||||
44
posmaster/poscore/management/commands/import_map.py
Normal file
44
posmaster/poscore/management/commands/import_map.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from __future__ import division
|
||||
import sqlite3
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.db import transaction
|
||||
from poscore.models import Region, Constellation, System, Planet, Moon
|
||||
|
||||
class Command(BaseCommand):
|
||||
args = '<map csv>'
|
||||
help = 'Imports the EVE Map from a CSV dump of the SDE table mapDenormalized'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
|
||||
# Connect to the sqlite3 DB
|
||||
db = sqlite3.connect(args[0])
|
||||
cur = db.cursor()
|
||||
|
||||
objs = []
|
||||
|
||||
# eveUnits
|
||||
print "Importing mapDenormalize..."
|
||||
cur.execute("""SELECT itemID, typeID, groupID, solarSystemID, constellationID, regionID, orbitID, x, y, z, itemName FROM mapDenormalize WHERE typeID in (3, 4, 5, 14) OR groupID = 7""")
|
||||
for row in cur.fetchall():
|
||||
id, type, group, solarid, constellationid, regionid, orbitid, x, y, z, name = row
|
||||
|
||||
if int(type) == 3:
|
||||
objs.append(Region(pk=id, name=name, x=0, y=0, z=0))
|
||||
elif int(type) == 4:
|
||||
objs.append(Constellation(pk=id, name=name, region_id=regionid, x=0, y=0, z=0))
|
||||
elif int(type) == 5:
|
||||
objs.append(System(pk=id, name=name, constellation_id=constellationid, x=0, y=0, z=0))
|
||||
elif int(group) == 7:
|
||||
objs.append(Planet(pk=id, name=name, system_id=solarid, x=x, y=y, z=z))
|
||||
elif int(type) == 14:
|
||||
objs.append(Moon(pk=id, name=name, planet_id=orbitid, x=x, y=y, z=z))
|
||||
print "Done"
|
||||
# Dump to DB
|
||||
|
||||
print 'Processing %d objects for commiting...' % len(objs)
|
||||
with transaction.commit_on_success():
|
||||
for i, x in enumerate(objs, start=1):
|
||||
if i % 1000 == 0: print "%d/%d (%d%%)" % (i, len(objs), round(i/len(objs) * 100))
|
||||
x.save()
|
||||
print 'Commited'
|
||||
60
posmaster/poscore/management/commands/import_types.py
Normal file
60
posmaster/poscore/management/commands/import_types.py
Normal file
@@ -0,0 +1,60 @@
|
||||
import sqlite3
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.db import transaction
|
||||
from poscore.models.types import TypeCategory, TypeGroup, Type, AttributeType, UnitType, TypeAttribute
|
||||
|
||||
class Command(BaseCommand):
|
||||
args = '<SDE SqliteDB>'
|
||||
help = 'Imports type data from the EVE SDE'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
|
||||
# Connect to the sqlite3 DB
|
||||
db = sqlite3.connect(args[0])
|
||||
cur = db.cursor()
|
||||
|
||||
objs = []
|
||||
|
||||
# eveUnits
|
||||
print "Importing eveUnits..."
|
||||
cur.execute("""SELECT unitID, unitName, displayName FROM eveUnits""")
|
||||
for row in cur.fetchall():
|
||||
objs.append(UnitType(pk=row[0], name=row[1], display_name=row[2] or ''))
|
||||
|
||||
# dgmAttributeTypes
|
||||
print "Importing dgmAttributeTypes..."
|
||||
cur.execute("""SELECT attributeID, attributeName, displayName, unitID FROM dgmAttributeTypes""")
|
||||
for row in cur.fetchall():
|
||||
objs.append(AttributeType(pk=row[0], name=row[1], display_name=row[2] or '', unit_id=row[3]))
|
||||
|
||||
# invCategories
|
||||
print "Importing invCategories..."
|
||||
cur.execute("""SELECT categoryID, categoryName FROM invCategories""")
|
||||
for row in cur.fetchall():
|
||||
objs.append(TypeCategory(pk=row[0], name=row[1]))
|
||||
|
||||
# invGroups
|
||||
print "Importing invGroups..."
|
||||
cur.execute("""SELECT groupID, groupName, categoryID FROM invGroups""")
|
||||
for row in cur.fetchall():
|
||||
objs.append(TypeGroup(pk=row[0], name=row[1], category_id=row[2]))
|
||||
|
||||
# invTypes
|
||||
print "Importing invTypes..."
|
||||
cur.execute("""SELECT typeID, typeName, capacity, groupID FROM invTypes""")
|
||||
for row in cur.fetchall():
|
||||
objs.append(Type(pk=row[0], name="".join(i for i in row[1] if ord(i)<128), capacity=row[2], group_id=row[3]))
|
||||
|
||||
# dgmTypeAttributes
|
||||
print "Importing dgmTypeAttributes..."
|
||||
cur.execute("""SELECT typeID, attributeID, valueInt, valueFloat FROM dgmTypeAttributes""")
|
||||
for row in cur.fetchall():
|
||||
objs.append(TypeAttribute(type_id=row[0], attribute_id=row[1], valueint=row[2], valuefloat=row[3]))
|
||||
|
||||
# Dump to DB
|
||||
print 'Processing %d objects for commiting...' % len(objs)
|
||||
with transaction.commit_on_success():
|
||||
for i, x in enumerate(objs, start=1):
|
||||
if i % 1000 == 0: print "%d/%d (%d%%)" % (i, len(objs), round(i/len(objs) * 100))
|
||||
x.save()
|
||||
print 'Commited'
|
||||
26
posmaster/poscore/management/commands/update_corporations.py
Normal file
26
posmaster/poscore/management/commands/update_corporations.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from django.db import transaction
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from poscore.models import Corporation
|
||||
from eveapi import EVEAPIConnection, Error
|
||||
|
||||
class Command(BaseCommand):
|
||||
args = ''
|
||||
help = 'Updates all corporations from the EVE API'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
api = EVEAPIConnection()
|
||||
|
||||
self.stdout.write('Updating %d corporations... ' % Corporation.objects.count())
|
||||
with transaction.commit_on_success():
|
||||
for corp in Corporation.objects.all():
|
||||
print corp.pk
|
||||
try:
|
||||
res = api.corp.CorporationSheet(corporationID=corp.pk)
|
||||
except Error:
|
||||
continue
|
||||
corp.name = res.corporationName
|
||||
corp.ticker = res.ticker
|
||||
if hasattr(res, 'allianceID'):
|
||||
corp.alliance_id = int(res.allianceID)
|
||||
corp.save()
|
||||
self.stdout.write('Done\n')
|
||||
5
posmaster/poscore/models/__init__.py
Normal file
5
posmaster/poscore/models/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from .locations import Location, Region, Constellation, System, Planet, Moon
|
||||
from .types import TypeCategory, TypeGroup, Type
|
||||
from .owners import Owner, Alliance, Corporation
|
||||
from .objects import InSpaceObject, Tower, Fuel, Silo
|
||||
from .api import APIKey
|
||||
13
posmaster/poscore/models/api.py
Normal file
13
posmaster/poscore/models/api.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from django.db import models
|
||||
|
||||
class APIKey(models.Model):
|
||||
|
||||
keyid = models.BigIntegerField('Key ID', primary_key=True)
|
||||
vcode = models.CharField('Verification Code', max_length=64)
|
||||
active = models.BooleanField('Active', default=True)
|
||||
|
||||
def auth(self, api):
|
||||
return api.auth(keyID=self.keyid, vCode=self.vcode)
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
79
posmaster/poscore/models/locations.py
Normal file
79
posmaster/poscore/models/locations.py
Normal file
@@ -0,0 +1,79 @@
|
||||
from django.db import models
|
||||
from .utils import InheritanceQuerySet
|
||||
from .owners import Corporation
|
||||
|
||||
class LocationManager(models.Manager):
|
||||
|
||||
def all_subclassed(self):
|
||||
return InheritanceQuerySet(model=self.model).select_subclasses()
|
||||
|
||||
class Location(models.Model):
|
||||
id = models.BigIntegerField('Location ID', primary_key=True)
|
||||
name = models.CharField('Location Name', max_length=200)
|
||||
x = models.BigIntegerField('X Location', null=True)
|
||||
y = models.BigIntegerField('Y Location', null=True)
|
||||
z = models.BigIntegerField('Z Location', null=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return "%(name)s (%(id)d)" % self.__dict__
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
|
||||
class Region(Location):
|
||||
|
||||
@property
|
||||
def systems(self):
|
||||
return System.objects.filter(constellation__in=self.constellations.all())
|
||||
|
||||
@property
|
||||
def planets(self):
|
||||
return Planet.objects.filter(system__constellation__in=self.constellations.all())
|
||||
|
||||
@property
|
||||
def moons(self):
|
||||
return Moon.objects.filter(planet__system__constellation__in=self.constellations.all())
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
|
||||
|
||||
class Constellation(Location):
|
||||
region = models.ForeignKey(Region, related_name='constellations')
|
||||
|
||||
@property
|
||||
def planets(self):
|
||||
return Planet.objects.filter(system__in=self.systems.all())
|
||||
|
||||
@property
|
||||
def moons(self):
|
||||
return Moon.objects.filter(planet__system__in=self.systems.all())
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
|
||||
|
||||
class System(Location):
|
||||
constellation = models.ForeignKey(Constellation, related_name='systems')
|
||||
owner = models.ForeignKey(Corporation, related_name='systems', null=True)
|
||||
|
||||
@property
|
||||
def moons(self):
|
||||
return Moon.objects.filter(planet__in=self.planets.all())
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
|
||||
|
||||
class Planet(Location):
|
||||
system = models.ForeignKey(System, related_name='planets')
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
|
||||
|
||||
class Moon(Location):
|
||||
planet = models.ForeignKey(Planet, related_name='moons')
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
158
posmaster/poscore/models/objects.py
Normal file
158
posmaster/poscore/models/objects.py
Normal file
@@ -0,0 +1,158 @@
|
||||
from math import sqrt
|
||||
from django.db import models
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
|
||||
from poscore.app_defines import *
|
||||
from .types import Type
|
||||
from .owners import Owner
|
||||
from .locations import System, Moon
|
||||
|
||||
class InSpaceObject(models.Model):
|
||||
"""Represents a object in space"""
|
||||
id = models.BigIntegerField('Object ID', primary_key=True)
|
||||
type = models.ForeignKey(Type, related_name='assets')
|
||||
owner = models.ForeignKey(Owner, related_name='assets', null=True)
|
||||
system = models.ForeignKey(System, related_name='assets')
|
||||
x = models.BigIntegerField('X Location', null=True)
|
||||
y = models.BigIntegerField('Y Location', null=True)
|
||||
z = models.BigIntegerField('Z Location', null=True)
|
||||
|
||||
@staticmethod
|
||||
def _calc_distance(sys1, sys2):
|
||||
"""Calculate the distance between two sets of 3d coordinates"""
|
||||
return sqrt((sys1.x-sys2.x)**2+(sys1.y-sys2.y)**2+(sys1.z-sys2.z)**2) / 1000
|
||||
|
||||
def distance(self, object):
|
||||
"""Calculate the distance between this object and another"""
|
||||
return InSpaceObject._calc_distance(self, object)
|
||||
|
||||
def nearby_objects(self, distance):
|
||||
"""Returns a queryset of nearby objects"""
|
||||
systemobjs = self.system.assets.exclude(pk=self.pk)
|
||||
outobj = []
|
||||
for obj in systemobjs:
|
||||
if self.distance(obj) <= distance:
|
||||
outobj.append(obj)
|
||||
return outobj
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
|
||||
def __unicode__(self):
|
||||
return '%s (%s)' % (self.type.name, self.system.name)
|
||||
|
||||
|
||||
class Tower(InSpaceObject):
|
||||
"""Tower or POS Tower in space"""
|
||||
|
||||
STATE_UNANCHORED = 0
|
||||
STATE_OFFLINE = 1
|
||||
STATE_ONLINING = 2
|
||||
STATE_REINFORCED = 3
|
||||
STATE_ONLINE = 4
|
||||
STATE_MISSING = 5
|
||||
|
||||
STATE_CHOICES = (
|
||||
(STATE_UNANCHORED, 'Unanchored'),
|
||||
(STATE_OFFLINE, 'Offline'),
|
||||
(STATE_ONLINING, 'Onlining'),
|
||||
(STATE_REINFORCED, 'Reinforced'),
|
||||
(STATE_ONLINE, 'Online'),
|
||||
(STATE_MISSING, 'Missing'),
|
||||
)
|
||||
|
||||
SIZE_SMALL = 1
|
||||
SIZE_MEDIUM = 2
|
||||
SIZE_LARGE = 3
|
||||
|
||||
SIZE_CHOICES = (
|
||||
(SIZE_SMALL, 'Small POS'),
|
||||
(SIZE_MEDIUM, 'Medium POS'),
|
||||
(SIZE_LARGE, 'Large POS'),
|
||||
)
|
||||
|
||||
name = models.CharField('Name', max_length=200)
|
||||
state = models.PositiveIntegerField('State', choices=STATE_CHOICES, default=STATE_UNANCHORED)
|
||||
moon = models.ForeignKey(Moon, related_name='structures')
|
||||
|
||||
state_datetime = models.DateTimeField('State Date/Time')
|
||||
online_datetime = models.DateTimeField('Online Date/Time')
|
||||
updated_datetime = models.DateTimeField('Last Update Date/Time', auto_now=True)
|
||||
|
||||
def modules(self):
|
||||
"""Find modules based on the tower's type attributes"""
|
||||
if not hasattr(self, '_max_distance'):
|
||||
self._max_distance = self.type.attributes.get(attribute_id=ATTRIBUTE_MAX_STRUCTURE_DISTANCE).value / 1000
|
||||
return self.nearby_objects(self._max_distance)
|
||||
|
||||
def power_usage(self):
|
||||
total = 0
|
||||
for mod in self.modules():
|
||||
total += mod.type.attributes.get(attribute_id=30).value
|
||||
return total
|
||||
|
||||
def cpu_usage(self):
|
||||
total = 0
|
||||
for mod in self.modules():
|
||||
total += mod.type.attributes.get(attribute_id=50).value
|
||||
return total
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
"""Returns the size of the POS based on its type"""
|
||||
if self.type.pk in []:
|
||||
return SIZE_SMALL
|
||||
elif self.type.pk in []:
|
||||
return SIZE_MEDIUM
|
||||
else:
|
||||
return SIZE_LARGE
|
||||
|
||||
def get_size_display(self):
|
||||
size = self.size
|
||||
for i, name in Tower.SIZE_CHOICE:
|
||||
if i == size:
|
||||
return name
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse_lazy('tower-detail', kwargs={'pk': self.pk})
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.type.group_id in TYPEGROUP_TOWERS:
|
||||
raise ValueError('You can\'t create a Tower with a non-tower typeID: %d - %s' % (self.type.pk, self.type.name))
|
||||
return super(Tower, self).save(*args, **kwargs)
|
||||
|
||||
|
||||
class Fuel(models.Model):
|
||||
|
||||
tower = models.ForeignKey(Tower, related_name='fuel')
|
||||
resource = models.ForeignKey(Type, related_name='+', limit_choices_to={'group__pk__in': TYPEGROUP_FUEL})
|
||||
level = models.PositiveIntegerField('Resource Level')
|
||||
|
||||
updated_datetime = models.DateTimeField('Last Update Date/Time', auto_now=True)
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
|
||||
|
||||
class Silo(InSpaceObject):
|
||||
|
||||
resource = models.ForeignKey(Type, related_name='+', limit_choices_to={'group__category__pk': 4})
|
||||
level = models.PositiveIntegerField('Resource Level', default=0)
|
||||
|
||||
emptied_datetime = models.DateTimeField('Last Emptied Date/Time')
|
||||
updated_datetime = models.DateTimeField('Last Update Date/Time', auto_now=True)
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
|
||||
|
||||
class JumpBridge(InSpaceObject):
|
||||
|
||||
level = models.PositiveIntegerField('Liquid Ozone Level', default=0)
|
||||
updated_datetime = models.DateTimeField('Last Update Date/Time', auto_now=True)
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
23
posmaster/poscore/models/owners.py
Normal file
23
posmaster/poscore/models/owners.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from django.db import models
|
||||
|
||||
class Owner(models.Model):
|
||||
id = models.BigIntegerField('Owner ID', primary_key=True)
|
||||
name = models.CharField('Owner Name', max_length=200)
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Alliance(Owner):
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
|
||||
class Corporation(Owner):
|
||||
"""Represents a EVE Corporation """
|
||||
alliance = models.ForeignKey(Alliance, related_name='corporations', null=True)
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
99
posmaster/poscore/models/types.py
Normal file
99
posmaster/poscore/models/types.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
|
||||
class TypeCategory(models.Model):
|
||||
id = models.BigIntegerField('Type Category ID', primary_key=True)
|
||||
name = models.CharField('Type Category Name', max_length=200)
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class TypeGroup(models.Model):
|
||||
id = models.BigIntegerField('Type Group ID', primary_key=True)
|
||||
category = models.ForeignKey(TypeCategory, related_name='groups')
|
||||
name = models.CharField('Type Group Name', max_length=200)
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Type(models.Model):
|
||||
"""Represents a EVE InvType"""
|
||||
id = models.BigIntegerField('Type ID', primary_key=True)
|
||||
group = models.ForeignKey(TypeGroup, related_name='types')
|
||||
name = models.CharField('Type Name', max_length=200)
|
||||
capacity = models.BigIntegerField('Capacity')
|
||||
|
||||
@property
|
||||
def image(self):
|
||||
return '%s/Type/%s_%s.png' % (getattr(settings, 'EVE_IMAGESERVER_URL', 'https://image.eveonline.com'), self.pk, getattr(settings, 'EVE_IMAGESERVER_TYPESIZE', 64))
|
||||
|
||||
def render(self, size):
|
||||
if size % 32:
|
||||
raise ValueError('Size isn\'t a multiple of 32')
|
||||
if size > 512:
|
||||
raise ValueError('Size is too large (max 512px)')
|
||||
return '%s/Render/%s_%s.png' % (getattr(settings, 'EVE_IMAGESERVER_URL', 'https://image.eveonline.com'), self.pk, size)
|
||||
|
||||
@property
|
||||
def attributes_list(self):
|
||||
return [(attr.attribute.display_name or attr.attribute.name, attr.get_value_display()) for attr in self.attributes.all()]
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class UnitType(models.Model):
|
||||
|
||||
id = models.BigIntegerField('Unit ID', primary_key=True)
|
||||
name = models.CharField('Unit Name', max_length=200)
|
||||
display_name = models.CharField('Display Name', max_length=200)
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class AttributeType(models.Model):
|
||||
|
||||
id = models.BigIntegerField('Attribute ID', primary_key=True)
|
||||
name = models.CharField('Attribute Name', max_length=200)
|
||||
display_name = models.CharField('Display Name', max_length=200)
|
||||
unit = models.ForeignKey(UnitType, related_name='+', null=True)
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class TypeAttribute(models.Model):
|
||||
|
||||
type = models.ForeignKey(Type, related_name='attributes')
|
||||
attribute = models.ForeignKey(AttributeType, related_name='+')
|
||||
valueint = models.BigIntegerField('Int Value', null=True)
|
||||
valuefloat = models.FloatField('Float Value', null=True)
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self.valuefloat or self.valueint
|
||||
|
||||
def get_value_display(self):
|
||||
if self.attribute.unit:
|
||||
return u'%d%s' % (self.value, self.attribute.unit.display_name)
|
||||
return self.value
|
||||
|
||||
class Meta:
|
||||
app_label = 'poscore'
|
||||
|
||||
def __unicode__(self):
|
||||
return self.attribute.name
|
||||
29
posmaster/poscore/models/utils.py
Normal file
29
posmaster/poscore/models/utils.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from django.db.models.fields.related import SingleRelatedObjectDescriptor
|
||||
from django.db.models.query import QuerySet
|
||||
|
||||
class InheritanceQuerySet(QuerySet):
|
||||
def select_subclasses(self, *subclasses):
|
||||
if not subclasses:
|
||||
subclasses = [o for o in dir(self.model)
|
||||
if isinstance(getattr(self.model, o), SingleRelatedObjectDescriptor)\
|
||||
and issubclass(getattr(self.model,o).related.model, self.model)]
|
||||
new_qs = self.select_related(*subclasses)
|
||||
new_qs.subclasses = subclasses
|
||||
return new_qs
|
||||
|
||||
def _clone(self, klass=None, setup=False, **kwargs):
|
||||
try:
|
||||
kwargs.update({'subclasses': self.subclasses})
|
||||
except AttributeError:
|
||||
pass
|
||||
return super(InheritanceQuerySet, self)._clone(klass, setup, **kwargs)
|
||||
|
||||
def iterator(self):
|
||||
iter = super(InheritanceQuerySet, self).iterator()
|
||||
if getattr(self, 'subclasses', False):
|
||||
for obj in iter:
|
||||
obj = [getattr(obj, s) for s in self.subclasses if getattr(obj, s)] or [obj]
|
||||
yield obj[0]
|
||||
else:
|
||||
for obj in iter:
|
||||
yield obj
|
||||
37
posmaster/poscore/templates/poscore/tower_detail.html
Normal file
37
posmaster/poscore/templates/poscore/tower_detail.html
Normal file
@@ -0,0 +1,37 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<h1>{{ tower.name }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
<div class="span9">
|
||||
{{ tower.type.name }}<br/>
|
||||
{{ tower.system.name }} - {{ tower.moon.name }}<br/>
|
||||
</p>
|
||||
</div>
|
||||
<div class="span3">
|
||||
<img src="{{ tower.type.image }}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<h2>Attributes</h2>
|
||||
|
||||
{{ tower.cpu_usage }}tf / {{ tower.power_usage }}MW
|
||||
|
||||
<table>
|
||||
{% for name, value in tower.type.attributes_list %}
|
||||
<tr><td>{{ name }}</td><td>{{ value }}</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
|
||||
<h2>Nearby Modules</h2>
|
||||
<table class="table">
|
||||
{% for module in modules %}
|
||||
<tr><td>{{ module.pk }} {{ module.type.pk }}</td><td>{{ module.type.name }}</td><td>{{ module.x }}/{{ module.y }}/{{ module.z }}</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
14
posmaster/poscore/templates/poscore/tower_list.html
Normal file
14
posmaster/poscore/templates/poscore/tower_list.html
Normal file
@@ -0,0 +1,14 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<table>
|
||||
{% regroup object_list by system as objects_by_system %}
|
||||
{% for system in objects_by_system %}
|
||||
<h2>{{ system.grouper.name }}</h2>
|
||||
<table>
|
||||
{% for tower in system.list %}
|
||||
<tr><td>{{ tower.moon.name }}</td><td><a href="{% url tower-detail pk=tower.pk %}">{{ tower.name }}</a></td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
16
posmaster/poscore/tests.py
Normal file
16
posmaster/poscore/tests.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
This file demonstrates writing tests using the unittest module. These will pass
|
||||
when you run "manage.py test".
|
||||
|
||||
Replace this with more appropriate tests for your application.
|
||||
"""
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
|
||||
class SimpleTest(TestCase):
|
||||
def test_basic_addition(self):
|
||||
"""
|
||||
Tests that 1 + 1 always equals 2.
|
||||
"""
|
||||
self.assertEqual(1 + 1, 2)
|
||||
7
posmaster/poscore/urls.py
Normal file
7
posmaster/poscore/urls.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.conf.urls import patterns, include, url
|
||||
from poscore.views import TowerListView, TowerDetailView
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^tower/$', TowerListView.as_view(), name='tower-list'),
|
||||
url(r'^tower/(?P<pk>\d+)/$', TowerDetailView.as_view(), name='tower-detail'),
|
||||
)
|
||||
17
posmaster/poscore/views.py
Normal file
17
posmaster/poscore/views.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Create your views here.
|
||||
from django.views.generic import ListView, DetailView
|
||||
|
||||
from poscore.models import Tower
|
||||
|
||||
class TowerListView(ListView):
|
||||
model = Tower
|
||||
|
||||
class TowerDetailView(DetailView):
|
||||
model = Tower
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super(TowerDetailView, self).get_context_data(**kwargs)
|
||||
ctx.update({
|
||||
'modules': self.object.modules
|
||||
})
|
||||
return ctx
|
||||
0
posmaster/posmaster/__init__.py
Normal file
0
posmaster/posmaster/__init__.py
Normal file
1
posmaster/posmaster/settings/__init__.py
Normal file
1
posmaster/posmaster/settings/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .development import *
|
||||
91
posmaster/posmaster/settings/base.py
Normal file
91
posmaster/posmaster/settings/base.py
Normal file
@@ -0,0 +1,91 @@
|
||||
import os.path
|
||||
import dj_database_url
|
||||
|
||||
# Debugging
|
||||
DEBUG = False
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
|
||||
# Database
|
||||
DATABASES = {'default': dj_database_url.config()}
|
||||
|
||||
# I18N/L10N
|
||||
TIME_ZONE = 'UTC'
|
||||
LANGUAGE_CODE = 'en'
|
||||
USE_I18N = True
|
||||
USE_L10N = True
|
||||
USE_TZ = True
|
||||
|
||||
# Site Config
|
||||
SITE_ID = 1
|
||||
SECRET_KEY = ''
|
||||
|
||||
# Media and Static files
|
||||
MEDIA_ROOT = ''
|
||||
MEDIA_URL = ''
|
||||
STATIC_ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', 'static')
|
||||
STATIC_URL = '/static/'
|
||||
STATICFILES_DIRS = (
|
||||
os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'static'),
|
||||
)
|
||||
STATICFILES_FINDERS = (
|
||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
||||
)
|
||||
|
||||
# Templates
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
)
|
||||
TEMPLATE_DIRS = (
|
||||
os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'templates'),
|
||||
)
|
||||
|
||||
# Applications
|
||||
INSTALLED_APPS = (
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.admin',
|
||||
'poscore',
|
||||
)
|
||||
ROOT_URLCONF = 'posmaster.urls'
|
||||
WSGI_APPLICATION = 'posmaster.wsgi.application'
|
||||
|
||||
# Middleware
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
)
|
||||
|
||||
# Logging
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'filters': {
|
||||
'require_debug_false': {
|
||||
'()': 'django.utils.log.RequireDebugFalse'
|
||||
}
|
||||
},
|
||||
'handlers': {
|
||||
'mail_admins': {
|
||||
'level': 'ERROR',
|
||||
'filters': ['require_debug_false'],
|
||||
'class': 'django.utils.log.AdminEmailHandler'
|
||||
}
|
||||
},
|
||||
'loggers': {
|
||||
'django.request': {
|
||||
'handlers': ['mail_admins'],
|
||||
'level': 'ERROR',
|
||||
'propagate': True,
|
||||
},
|
||||
}
|
||||
}
|
||||
4
posmaster/posmaster/settings/development.py
Normal file
4
posmaster/posmaster/settings/development.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from .base import *
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
1
posmaster/posmaster/settings/production.py
Normal file
1
posmaster/posmaster/settings/production.py
Normal file
@@ -0,0 +1 @@
|
||||
from .base import *
|
||||
815
posmaster/posmaster/static/css/bootstrap-responsive.css
vendored
Normal file
815
posmaster/posmaster/static/css/bootstrap-responsive.css
vendored
Normal file
@@ -0,0 +1,815 @@
|
||||
/*!
|
||||
* Bootstrap Responsive v2.0.4
|
||||
*
|
||||
* Copyright 2012 Twitter, Inc
|
||||
* Licensed under the Apache License v2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Designed and built with all the love in the world @twitter by @mdo and @fat.
|
||||
*/
|
||||
|
||||
.clearfix {
|
||||
*zoom: 1;
|
||||
}
|
||||
|
||||
.clearfix:before,
|
||||
.clearfix:after {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.clearfix:after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.hide-text {
|
||||
font: 0/0 a;
|
||||
color: transparent;
|
||||
text-shadow: none;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.input-block-level {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 28px;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-ms-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.visible-phone {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.visible-tablet {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.hidden-desktop {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.visible-phone {
|
||||
display: inherit !important;
|
||||
}
|
||||
.hidden-phone {
|
||||
display: none !important;
|
||||
}
|
||||
.hidden-desktop {
|
||||
display: inherit !important;
|
||||
}
|
||||
.visible-desktop {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) and (max-width: 979px) {
|
||||
.visible-tablet {
|
||||
display: inherit !important;
|
||||
}
|
||||
.hidden-tablet {
|
||||
display: none !important;
|
||||
}
|
||||
.hidden-desktop {
|
||||
display: inherit !important;
|
||||
}
|
||||
.visible-desktop {
|
||||
display: none !important ;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.nav-collapse {
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
}
|
||||
.page-header h1 small {
|
||||
display: block;
|
||||
line-height: 18px;
|
||||
}
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
.form-horizontal .control-group > label {
|
||||
float: none;
|
||||
width: auto;
|
||||
padding-top: 0;
|
||||
text-align: left;
|
||||
}
|
||||
.form-horizontal .controls {
|
||||
margin-left: 0;
|
||||
}
|
||||
.form-horizontal .control-list {
|
||||
padding-top: 0;
|
||||
}
|
||||
.form-horizontal .form-actions {
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
.modal {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
left: 10px;
|
||||
width: auto;
|
||||
margin: 0;
|
||||
}
|
||||
.modal.fade.in {
|
||||
top: auto;
|
||||
}
|
||||
.modal-header .close {
|
||||
padding: 10px;
|
||||
margin: -10px;
|
||||
}
|
||||
.carousel-caption {
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
body {
|
||||
padding-right: 20px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
.navbar-fixed-top,
|
||||
.navbar-fixed-bottom {
|
||||
margin-right: -20px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
.container-fluid {
|
||||
padding: 0;
|
||||
}
|
||||
.dl-horizontal dt {
|
||||
float: none;
|
||||
width: auto;
|
||||
clear: none;
|
||||
text-align: left;
|
||||
}
|
||||
.dl-horizontal dd {
|
||||
margin-left: 0;
|
||||
}
|
||||
.container {
|
||||
width: auto;
|
||||
}
|
||||
.row-fluid {
|
||||
width: 100%;
|
||||
}
|
||||
.row,
|
||||
.thumbnails {
|
||||
margin-left: 0;
|
||||
}
|
||||
[class*="span"],
|
||||
.row-fluid [class*="span"] {
|
||||
display: block;
|
||||
float: none;
|
||||
width: auto;
|
||||
margin-left: 0;
|
||||
}
|
||||
.input-large,
|
||||
.input-xlarge,
|
||||
.input-xxlarge,
|
||||
input[class*="span"],
|
||||
select[class*="span"],
|
||||
textarea[class*="span"],
|
||||
.uneditable-input {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 28px;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-ms-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.input-prepend input,
|
||||
.input-append input,
|
||||
.input-prepend input[class*="span"],
|
||||
.input-append input[class*="span"] {
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) and (max-width: 979px) {
|
||||
.row {
|
||||
margin-left: -20px;
|
||||
*zoom: 1;
|
||||
}
|
||||
.row:before,
|
||||
.row:after {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
.row:after {
|
||||
clear: both;
|
||||
}
|
||||
[class*="span"] {
|
||||
float: left;
|
||||
margin-left: 20px;
|
||||
}
|
||||
.container,
|
||||
.navbar-fixed-top .container,
|
||||
.navbar-fixed-bottom .container {
|
||||
width: 724px;
|
||||
}
|
||||
.span12 {
|
||||
width: 724px;
|
||||
}
|
||||
.span11 {
|
||||
width: 662px;
|
||||
}
|
||||
.span10 {
|
||||
width: 600px;
|
||||
}
|
||||
.span9 {
|
||||
width: 538px;
|
||||
}
|
||||
.span8 {
|
||||
width: 476px;
|
||||
}
|
||||
.span7 {
|
||||
width: 414px;
|
||||
}
|
||||
.span6 {
|
||||
width: 352px;
|
||||
}
|
||||
.span5 {
|
||||
width: 290px;
|
||||
}
|
||||
.span4 {
|
||||
width: 228px;
|
||||
}
|
||||
.span3 {
|
||||
width: 166px;
|
||||
}
|
||||
.span2 {
|
||||
width: 104px;
|
||||
}
|
||||
.span1 {
|
||||
width: 42px;
|
||||
}
|
||||
.offset12 {
|
||||
margin-left: 764px;
|
||||
}
|
||||
.offset11 {
|
||||
margin-left: 702px;
|
||||
}
|
||||
.offset10 {
|
||||
margin-left: 640px;
|
||||
}
|
||||
.offset9 {
|
||||
margin-left: 578px;
|
||||
}
|
||||
.offset8 {
|
||||
margin-left: 516px;
|
||||
}
|
||||
.offset7 {
|
||||
margin-left: 454px;
|
||||
}
|
||||
.offset6 {
|
||||
margin-left: 392px;
|
||||
}
|
||||
.offset5 {
|
||||
margin-left: 330px;
|
||||
}
|
||||
.offset4 {
|
||||
margin-left: 268px;
|
||||
}
|
||||
.offset3 {
|
||||
margin-left: 206px;
|
||||
}
|
||||
.offset2 {
|
||||
margin-left: 144px;
|
||||
}
|
||||
.offset1 {
|
||||
margin-left: 82px;
|
||||
}
|
||||
.row-fluid {
|
||||
width: 100%;
|
||||
*zoom: 1;
|
||||
}
|
||||
.row-fluid:before,
|
||||
.row-fluid:after {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
.row-fluid:after {
|
||||
clear: both;
|
||||
}
|
||||
.row-fluid [class*="span"] {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 100%;
|
||||
min-height: 28px;
|
||||
margin-left: 2.762430939%;
|
||||
*margin-left: 2.709239449638298%;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-ms-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.row-fluid [class*="span"]:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
.row-fluid .span12 {
|
||||
width: 99.999999993%;
|
||||
*width: 99.9468085036383%;
|
||||
}
|
||||
.row-fluid .span11 {
|
||||
width: 91.436464082%;
|
||||
*width: 91.38327259263829%;
|
||||
}
|
||||
.row-fluid .span10 {
|
||||
width: 82.87292817100001%;
|
||||
*width: 82.8197366816383%;
|
||||
}
|
||||
.row-fluid .span9 {
|
||||
width: 74.30939226%;
|
||||
*width: 74.25620077063829%;
|
||||
}
|
||||
.row-fluid .span8 {
|
||||
width: 65.74585634900001%;
|
||||
*width: 65.6926648596383%;
|
||||
}
|
||||
.row-fluid .span7 {
|
||||
width: 57.182320438000005%;
|
||||
*width: 57.129128948638304%;
|
||||
}
|
||||
.row-fluid .span6 {
|
||||
width: 48.618784527%;
|
||||
*width: 48.5655930376383%;
|
||||
}
|
||||
.row-fluid .span5 {
|
||||
width: 40.055248616%;
|
||||
*width: 40.0020571266383%;
|
||||
}
|
||||
.row-fluid .span4 {
|
||||
width: 31.491712705%;
|
||||
*width: 31.4385212156383%;
|
||||
}
|
||||
.row-fluid .span3 {
|
||||
width: 22.928176794%;
|
||||
*width: 22.874985304638297%;
|
||||
}
|
||||
.row-fluid .span2 {
|
||||
width: 14.364640883%;
|
||||
*width: 14.311449393638298%;
|
||||
}
|
||||
.row-fluid .span1 {
|
||||
width: 5.801104972%;
|
||||
*width: 5.747913482638298%;
|
||||
}
|
||||
input,
|
||||
textarea,
|
||||
.uneditable-input {
|
||||
margin-left: 0;
|
||||
}
|
||||
input.span12,
|
||||
textarea.span12,
|
||||
.uneditable-input.span12 {
|
||||
width: 714px;
|
||||
}
|
||||
input.span11,
|
||||
textarea.span11,
|
||||
.uneditable-input.span11 {
|
||||
width: 652px;
|
||||
}
|
||||
input.span10,
|
||||
textarea.span10,
|
||||
.uneditable-input.span10 {
|
||||
width: 590px;
|
||||
}
|
||||
input.span9,
|
||||
textarea.span9,
|
||||
.uneditable-input.span9 {
|
||||
width: 528px;
|
||||
}
|
||||
input.span8,
|
||||
textarea.span8,
|
||||
.uneditable-input.span8 {
|
||||
width: 466px;
|
||||
}
|
||||
input.span7,
|
||||
textarea.span7,
|
||||
.uneditable-input.span7 {
|
||||
width: 404px;
|
||||
}
|
||||
input.span6,
|
||||
textarea.span6,
|
||||
.uneditable-input.span6 {
|
||||
width: 342px;
|
||||
}
|
||||
input.span5,
|
||||
textarea.span5,
|
||||
.uneditable-input.span5 {
|
||||
width: 280px;
|
||||
}
|
||||
input.span4,
|
||||
textarea.span4,
|
||||
.uneditable-input.span4 {
|
||||
width: 218px;
|
||||
}
|
||||
input.span3,
|
||||
textarea.span3,
|
||||
.uneditable-input.span3 {
|
||||
width: 156px;
|
||||
}
|
||||
input.span2,
|
||||
textarea.span2,
|
||||
.uneditable-input.span2 {
|
||||
width: 94px;
|
||||
}
|
||||
input.span1,
|
||||
textarea.span1,
|
||||
.uneditable-input.span1 {
|
||||
width: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.row {
|
||||
margin-left: -30px;
|
||||
*zoom: 1;
|
||||
}
|
||||
.row:before,
|
||||
.row:after {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
.row:after {
|
||||
clear: both;
|
||||
}
|
||||
[class*="span"] {
|
||||
float: left;
|
||||
margin-left: 30px;
|
||||
}
|
||||
.container,
|
||||
.navbar-fixed-top .container,
|
||||
.navbar-fixed-bottom .container {
|
||||
width: 1170px;
|
||||
}
|
||||
.span12 {
|
||||
width: 1170px;
|
||||
}
|
||||
.span11 {
|
||||
width: 1070px;
|
||||
}
|
||||
.span10 {
|
||||
width: 970px;
|
||||
}
|
||||
.span9 {
|
||||
width: 870px;
|
||||
}
|
||||
.span8 {
|
||||
width: 770px;
|
||||
}
|
||||
.span7 {
|
||||
width: 670px;
|
||||
}
|
||||
.span6 {
|
||||
width: 570px;
|
||||
}
|
||||
.span5 {
|
||||
width: 470px;
|
||||
}
|
||||
.span4 {
|
||||
width: 370px;
|
||||
}
|
||||
.span3 {
|
||||
width: 270px;
|
||||
}
|
||||
.span2 {
|
||||
width: 170px;
|
||||
}
|
||||
.span1 {
|
||||
width: 70px;
|
||||
}
|
||||
.offset12 {
|
||||
margin-left: 1230px;
|
||||
}
|
||||
.offset11 {
|
||||
margin-left: 1130px;
|
||||
}
|
||||
.offset10 {
|
||||
margin-left: 1030px;
|
||||
}
|
||||
.offset9 {
|
||||
margin-left: 930px;
|
||||
}
|
||||
.offset8 {
|
||||
margin-left: 830px;
|
||||
}
|
||||
.offset7 {
|
||||
margin-left: 730px;
|
||||
}
|
||||
.offset6 {
|
||||
margin-left: 630px;
|
||||
}
|
||||
.offset5 {
|
||||
margin-left: 530px;
|
||||
}
|
||||
.offset4 {
|
||||
margin-left: 430px;
|
||||
}
|
||||
.offset3 {
|
||||
margin-left: 330px;
|
||||
}
|
||||
.offset2 {
|
||||
margin-left: 230px;
|
||||
}
|
||||
.offset1 {
|
||||
margin-left: 130px;
|
||||
}
|
||||
.row-fluid {
|
||||
width: 100%;
|
||||
*zoom: 1;
|
||||
}
|
||||
.row-fluid:before,
|
||||
.row-fluid:after {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
.row-fluid:after {
|
||||
clear: both;
|
||||
}
|
||||
.row-fluid [class*="span"] {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 100%;
|
||||
min-height: 28px;
|
||||
margin-left: 2.564102564%;
|
||||
*margin-left: 2.510911074638298%;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-ms-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.row-fluid [class*="span"]:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
.row-fluid .span12 {
|
||||
width: 100%;
|
||||
*width: 99.94680851063829%;
|
||||
}
|
||||
.row-fluid .span11 {
|
||||
width: 91.45299145300001%;
|
||||
*width: 91.3997999636383%;
|
||||
}
|
||||
.row-fluid .span10 {
|
||||
width: 82.905982906%;
|
||||
*width: 82.8527914166383%;
|
||||
}
|
||||
.row-fluid .span9 {
|
||||
width: 74.358974359%;
|
||||
*width: 74.30578286963829%;
|
||||
}
|
||||
.row-fluid .span8 {
|
||||
width: 65.81196581200001%;
|
||||
*width: 65.7587743226383%;
|
||||
}
|
||||
.row-fluid .span7 {
|
||||
width: 57.264957265%;
|
||||
*width: 57.2117657756383%;
|
||||
}
|
||||
.row-fluid .span6 {
|
||||
width: 48.717948718%;
|
||||
*width: 48.6647572286383%;
|
||||
}
|
||||
.row-fluid .span5 {
|
||||
width: 40.170940171000005%;
|
||||
*width: 40.117748681638304%;
|
||||
}
|
||||
.row-fluid .span4 {
|
||||
width: 31.623931624%;
|
||||
*width: 31.5707401346383%;
|
||||
}
|
||||
.row-fluid .span3 {
|
||||
width: 23.076923077%;
|
||||
*width: 23.0237315876383%;
|
||||
}
|
||||
.row-fluid .span2 {
|
||||
width: 14.529914530000001%;
|
||||
*width: 14.4767230406383%;
|
||||
}
|
||||
.row-fluid .span1 {
|
||||
width: 5.982905983%;
|
||||
*width: 5.929714493638298%;
|
||||
}
|
||||
input,
|
||||
textarea,
|
||||
.uneditable-input {
|
||||
margin-left: 0;
|
||||
}
|
||||
input.span12,
|
||||
textarea.span12,
|
||||
.uneditable-input.span12 {
|
||||
width: 1160px;
|
||||
}
|
||||
input.span11,
|
||||
textarea.span11,
|
||||
.uneditable-input.span11 {
|
||||
width: 1060px;
|
||||
}
|
||||
input.span10,
|
||||
textarea.span10,
|
||||
.uneditable-input.span10 {
|
||||
width: 960px;
|
||||
}
|
||||
input.span9,
|
||||
textarea.span9,
|
||||
.uneditable-input.span9 {
|
||||
width: 860px;
|
||||
}
|
||||
input.span8,
|
||||
textarea.span8,
|
||||
.uneditable-input.span8 {
|
||||
width: 760px;
|
||||
}
|
||||
input.span7,
|
||||
textarea.span7,
|
||||
.uneditable-input.span7 {
|
||||
width: 660px;
|
||||
}
|
||||
input.span6,
|
||||
textarea.span6,
|
||||
.uneditable-input.span6 {
|
||||
width: 560px;
|
||||
}
|
||||
input.span5,
|
||||
textarea.span5,
|
||||
.uneditable-input.span5 {
|
||||
width: 460px;
|
||||
}
|
||||
input.span4,
|
||||
textarea.span4,
|
||||
.uneditable-input.span4 {
|
||||
width: 360px;
|
||||
}
|
||||
input.span3,
|
||||
textarea.span3,
|
||||
.uneditable-input.span3 {
|
||||
width: 260px;
|
||||
}
|
||||
input.span2,
|
||||
textarea.span2,
|
||||
.uneditable-input.span2 {
|
||||
width: 160px;
|
||||
}
|
||||
input.span1,
|
||||
textarea.span1,
|
||||
.uneditable-input.span1 {
|
||||
width: 60px;
|
||||
}
|
||||
.thumbnails {
|
||||
margin-left: -30px;
|
||||
}
|
||||
.thumbnails > li {
|
||||
margin-left: 30px;
|
||||
}
|
||||
.row-fluid .thumbnails {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 979px) {
|
||||
body {
|
||||
padding-top: 0;
|
||||
}
|
||||
.navbar-fixed-top,
|
||||
.navbar-fixed-bottom {
|
||||
position: static;
|
||||
}
|
||||
.navbar-fixed-top {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
.navbar-fixed-bottom {
|
||||
margin-top: 18px;
|
||||
}
|
||||
.navbar-fixed-top .navbar-inner,
|
||||
.navbar-fixed-bottom .navbar-inner {
|
||||
padding: 5px;
|
||||
}
|
||||
.navbar .container {
|
||||
width: auto;
|
||||
padding: 0;
|
||||
}
|
||||
.navbar .brand {
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
margin: 0 0 0 -5px;
|
||||
}
|
||||
.nav-collapse {
|
||||
clear: both;
|
||||
}
|
||||
.nav-collapse .nav {
|
||||
float: none;
|
||||
margin: 0 0 9px;
|
||||
}
|
||||
.nav-collapse .nav > li {
|
||||
float: none;
|
||||
}
|
||||
.nav-collapse .nav > li > a {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.nav-collapse .nav > .divider-vertical {
|
||||
display: none;
|
||||
}
|
||||
.nav-collapse .nav .nav-header {
|
||||
color: #999999;
|
||||
text-shadow: none;
|
||||
}
|
||||
.nav-collapse .nav > li > a,
|
||||
.nav-collapse .dropdown-menu a {
|
||||
padding: 6px 15px;
|
||||
font-weight: bold;
|
||||
color: #999999;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.nav-collapse .btn {
|
||||
padding: 4px 10px 4px;
|
||||
font-weight: normal;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.nav-collapse .dropdown-menu li + li a {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.nav-collapse .nav > li > a:hover,
|
||||
.nav-collapse .dropdown-menu a:hover {
|
||||
background-color: #222222;
|
||||
}
|
||||
.nav-collapse.in .btn-group {
|
||||
padding: 0;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.nav-collapse .dropdown-menu {
|
||||
position: static;
|
||||
top: auto;
|
||||
left: auto;
|
||||
display: block;
|
||||
float: none;
|
||||
max-width: none;
|
||||
padding: 0;
|
||||
margin: 0 15px;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
-webkit-border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.nav-collapse .dropdown-menu:before,
|
||||
.nav-collapse .dropdown-menu:after {
|
||||
display: none;
|
||||
}
|
||||
.nav-collapse .dropdown-menu .divider {
|
||||
display: none;
|
||||
}
|
||||
.nav-collapse .navbar-form,
|
||||
.nav-collapse .navbar-search {
|
||||
float: none;
|
||||
padding: 9px 15px;
|
||||
margin: 9px 0;
|
||||
border-top: 1px solid #222222;
|
||||
border-bottom: 1px solid #222222;
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
-moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.navbar .nav-collapse .nav.pull-right {
|
||||
float: none;
|
||||
margin-left: 0;
|
||||
}
|
||||
.nav-collapse,
|
||||
.nav-collapse.collapse {
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.navbar .btn-navbar {
|
||||
display: block;
|
||||
}
|
||||
.navbar-static .navbar-inner {
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 980px) {
|
||||
.nav-collapse.collapse {
|
||||
height: auto !important;
|
||||
overflow: visible !important;
|
||||
}
|
||||
}
|
||||
9
posmaster/posmaster/static/css/bootstrap-responsive.min.css
vendored
Normal file
9
posmaster/posmaster/static/css/bootstrap-responsive.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
4983
posmaster/posmaster/static/css/bootstrap.css
vendored
Normal file
4983
posmaster/posmaster/static/css/bootstrap.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
posmaster/posmaster/static/css/bootstrap.min.css
vendored
Normal file
9
posmaster/posmaster/static/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
posmaster/posmaster/static/img/glyphicons-halflings-white.png
Normal file
BIN
posmaster/posmaster/static/img/glyphicons-halflings-white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.6 KiB |
BIN
posmaster/posmaster/static/img/glyphicons-halflings.png
Normal file
BIN
posmaster/posmaster/static/img/glyphicons-halflings.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
1825
posmaster/posmaster/static/js/bootstrap.js
vendored
Normal file
1825
posmaster/posmaster/static/js/bootstrap.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
6
posmaster/posmaster/static/js/bootstrap.min.js
vendored
Normal file
6
posmaster/posmaster/static/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
19
posmaster/posmaster/templates/base.html
Normal file
19
posmaster/posmaster/templates/base.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>POSMaster</title>
|
||||
<link href="{{ STATIC_URL }}css/bootstrap.css" rel="stylesheet">
|
||||
<link href="{{ STATIC_URL }}css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link rel="shortcut icon" href="{{ STATIC_URL }}img/favicon.ico">
|
||||
<link rel="apple-touch-icon" href="{{ STATIC_URL }}img/apple-touch-icon-57-precomposed.png">
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
10
posmaster/posmaster/urls.py
Normal file
10
posmaster/posmaster/urls.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from django.conf.urls import patterns, include, url
|
||||
|
||||
# Uncomment the next two lines to enable the admin:
|
||||
from django.contrib import admin
|
||||
admin.autodiscover()
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'', include('poscore.urls')),
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
)
|
||||
28
posmaster/posmaster/wsgi.py
Normal file
28
posmaster/posmaster/wsgi.py
Normal file
@@ -0,0 +1,28 @@
|
||||
"""
|
||||
WSGI config for posmaster project.
|
||||
|
||||
This module contains the WSGI application used by Django's development server
|
||||
and any production WSGI deployments. It should expose a module-level variable
|
||||
named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover
|
||||
this application via the ``WSGI_APPLICATION`` setting.
|
||||
|
||||
Usually you will have the standard Django WSGI application here, but it also
|
||||
might make sense to replace the whole Django WSGI application with a custom one
|
||||
that later delegates to the Django one. For example, you could introduce WSGI
|
||||
middleware here, or combine a Django application with an application of another
|
||||
framework.
|
||||
|
||||
"""
|
||||
import os
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "posmaster.settings")
|
||||
|
||||
# This application object is used by any WSGI server configured to use this
|
||||
# file. This includes Django's development server, if the WSGI_APPLICATION
|
||||
# setting points here.
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
application = get_wsgi_application()
|
||||
|
||||
# Apply WSGI middleware here.
|
||||
# from helloworld.wsgi import HelloWorldApplication
|
||||
# application = HelloWorldApplication(application)
|
||||
10
requirements.txt
Normal file
10
requirements.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Django==1.4.1
|
||||
South==0.7.6
|
||||
django-debug-toolbar==0.9.4
|
||||
-e git://github.com/nikdoof/django-braces.git#egg=braces
|
||||
-e git://github.com/nikdoof/eveapi.git#egg=eveapi
|
||||
-e git://github.com/nikdoof/django-eveigb.git#egg=django-eveigb
|
||||
django-modeldict==1.3.1
|
||||
-e git://github.com/mvasilkov/django-google-charts.git#egg=django-google-charts
|
||||
raven
|
||||
dj-database-url==0.2.1
|
||||
Reference in New Issue
Block a user