1 # -*- coding: utf-8 -*-
3 from __future__ import division
5 from datetime import datetime
6 from random import SystemRandom
7 from django.db import models
8 from django.contrib.auth.models import get_hexdigest
9 from django.utils import html
11 from ais.common import Nmea, mmsi_to_strmmsi, nice_timedelta_str
13 class UserMessageCategory(models.Model):
14 id = models.CharField(max_length=10, primary_key=True)
16 db_table = u'user_message_category'
18 class UserMessage(models.Model):
19 id = models.AutoField(primary_key=True)
20 user = models.ForeignKey('User')
21 category = models.ForeignKey(UserMessageCategory, db_column='user_message_category_id')
22 txt = models.TextField()
24 db_table = u'user_message'
26 class User(models.Model):
27 id = models.AutoField(primary_key=True)
28 login = models.CharField(max_length=16, unique=True)
29 password_hash = models.CharField(max_length=75)
30 name = models.CharField(max_length=50)
31 email = models.EmailField()
32 father = models.ForeignKey('User')
33 creation_datetime = models.DateTimeField(auto_now_add=True)
34 phone = models.CharField(max_length=20, blank=True)
35 access_datetime = models.DateTimeField(blank=True, null=True)
40 def __unicode__(self):
43 def set_password(self, raw_password):
46 salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
47 hsh = get_hexdigest(algo, salt, raw_password)
48 self.password_hash = '%s$%s$%s' % (algo, salt, hsh)
49 self.info('Password changed') # FIXME
51 def check_password(self, raw_password):
52 algo, salt, hsh = self.password_hash.split('$')
53 return hsh == get_hexdigest(algo, salt, raw_password)
56 def update_access_datetime(self):
57 self.access_datetime = datetime.utcnow()
60 def get_and_delete_messages(self):
63 def is_admin_by(self, user_id):
64 if self.id == user_id:
66 if self.father_id is None:
68 return self.father.is_admin_by(user_id)
70 def get_messages(self):
71 messages = UserMessage.objects.filter(user__id = self.id)
73 [ {'category': message.category, \
75 for message in messages \
80 def info(self, message):
81 UserMessage(user_id = self.id, category_id=u'info', txt=html.escape(message)).save()
83 def error(self, message):
84 UserMessage(user_id = self.id, category_id=u'error', txt=html.escape(message)).save()
86 def check_sandbox_access(self, source_user=None):
89 FleetUser.objects.get(fleet = SANDBOX_FLEET, user = self)
90 except FleetUser.DoesNotExist:
93 fu.fleet_id = SANDBOX_FLEET
96 source_user.info("%s was granted access to 'sandbox' fleet" % self.login)
99 class Vessel(models.Model):
100 mmsi = models.IntegerField(primary_key=True)
101 name = models.CharField(max_length=20)
102 imo = models.IntegerField()
103 callsign = models.CharField(max_length=7)
104 type = models.IntegerField(default=0)
105 destination = models.CharField(max_length=20, blank=True, null=True)
106 updated = models.DateTimeField()
107 source = models.CharField(max_length=8)
108 dim_bow = models.IntegerField(default=0)
109 dim_stern = models.IntegerField(default=0)
110 dim_port = models.IntegerField(default=0)
111 dim_starboard = models.IntegerField(default=0)
112 eta = models.CharField(max_length=8, default='00002460') # format MMDDhhmm
115 def __unicode__(self):
116 return unicode(self.mmsi) # FIXME
117 def get_last_nmea(self):
118 strmmsi = mmsi_to_strmmsi(self.mmsi)
119 return Nmea.new_from_lastinfo(strmmsi)
122 class Fleet(models.Model):
123 id = models.AutoField(primary_key=True)
124 name = models.CharField(max_length=50)
125 vessel = models.ManyToManyField(Vessel, through='FleetVessel')
126 description = models.TextField()
129 def __unicode__(self):
131 def vessel_count(self):
132 return FleetVessel.objects.filter(fleet=self.id).count()
133 def user_count(self):
134 return FleetUser.objects.filter(fleet=self.id).count()
136 if os.path.exists('/var/lib/ais/cron/fleets/%s.cron' % self.name):
141 class FleetUser(models.Model):
142 id = models.AutoField(primary_key=True)
143 fleet = models.ForeignKey(Fleet) #, db_column='fleet_id', to_field='id')
144 user = models.ForeignKey(User)
146 db_table = u'fleet_user'
148 class FleetVessel(models.Model):
149 id = models.AutoField(primary_key=True)
150 fleet = models.ForeignKey(Fleet, db_column='fleet_id', to_field='id')
151 vessel = models.ForeignKey(Vessel, db_column='mmsi', to_field='mmsi')
153 db_table = u'fleet_vessel'
155 ## manual input source
156 #class MiSource(models.Model):
157 # id = models.IntegerField(primary_key=True)
158 # userid = models.IntegerField()
159 # name = models.TextField(unique=True)
161 # db_table = u'mi_source'
163 ## manual input vessel
164 #class MiVessel(models.Model):
165 # mmsi_txt = models.TextField(primary_key=True) # This field type is a guess.
167 # db_table = u'mi_vessel'
171 #class Ppuser(models.Model):
172 # usr = models.TextField(primary_key=True) # This field type is a guess.
173 # lat = models.FloatField()
174 # lon = models.FloatField()
176 # db_table = u'ppuser'
178 #class Plane(models.Model):
179 # flight = models.CharField(max_length=8)
180 # reg = models.CharField(max_length=8)
181 # ads = models.CharField(max_length=8)
182 # type = models.CharField(max_length=4)
183 # usr = models.TextField() # This field type is a guess.
184 # updated = models.DateTimeField()
186 # db_table = u'plane'
190 class News(models.Model):
191 id = models.AutoField(primary_key=True)
192 created = models.DateTimeField()
193 updated = models.DateTimeField()
194 title = models.TextField()
195 txt = models.TextField()
200 class Job(models.Model):
201 def make_unique_job_id():
204 source = u'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
207 result += source[int(rnd.random()*len(source))]
209 return make_id() # TODO check it's unique
211 id = models.CharField(primary_key=True, max_length=8, default=make_unique_job_id)
212 user = models.ForeignKey(User)
213 queue_time = models.DateTimeField(auto_now_add=True)
214 start_time = models.DateTimeField(blank=True, null=True)
215 finish_time = models.DateTimeField(blank=True, null=True)
216 command = models.TextField()
217 friendly_filename = models.CharField(max_length=255)
218 pid = models.IntegerField(blank=True, null=True)
219 result = models.IntegerField(blank=True, null=True)
220 archive_time = models.DateTimeField(blank=True, null=True)
221 notify = models.CharField(max_length=1, blank=True, null=True)
223 def queue_rank(self):
224 return Job.objects.filter(queue_time__lt=self.queue_time).filter(start_time__isnull=True).count() + 1
228 return Job.objects.filter(start_time__isnull=True).count()
230 def process_time(self):
231 dt = self.finish_time - self.start_time
232 return nice_timedelta_str(dt)
234 def running_time(self):
235 dt = datetime.utcnow() - self.start_time
236 return nice_timedelta_str(dt)
241 strstats = file('/proc/%s/stat' % self.pid).read()
246 # "getconf CLK_TCK" = 100 -> 1 tick = 1/100 seconds
247 strstats = strstats.rstrip('\n').split(' ')
248 for i, key in enumerate(('pid', 'comm', 'state', 'ppid', 'pgrp', 'session', 'tty_nr', 'tpgid', 'flags', 'minflt', 'cminflt', 'majflt', 'cmajflt', 'utime', 'stime', 'cutime', 'cstime', 'priority', 'nice', 'num_threads', 'itrealvalue', 'starttime', 'vsize', 'rss', 'rsslim', 'startcode', 'endcode', 'startstack', 'kstkesp', 'kstkeip', 'signal', 'blocked', 'sigignore', 'sigcatch', 'wchan', 'nswap', 'cnswap', 'exit_signal', 'processor', 'rt_priority', 'policy', 'delayacct_blkio_ticks', 'guest_time', 'cguest_time')):
249 result[key] = strstats[i]
252 def get_sucess_size(self):
253 extension = os.path.splitext(self.friendly_filename)[-1]
254 filename = '/var/lib/ais/jobs/%s%s' % (self.id, extension)
255 return os.path.getsize(filename)
259 ordering = ('queue_time',)