replace job extension by a friendly filename.
[ais.git] / bin / djais / models.py
1 # -*- coding: utf-8 -*-
2
3 import os, os.path
4 from datetime import datetime
5 from random import SystemRandom
6 from django.db import models
7 from django.contrib.auth.models import get_hexdigest
8 from django.utils import html
9
10 from ais.common import Nmea, mmsi_to_strmmsi, nice_timedelta_str
11
12 class UserMessageCategory(models.Model):
13     id = models.CharField(max_length=10, primary_key=True)
14     class Meta:
15         db_table = u'user_message_category'
16
17 class UserMessage(models.Model):
18     id = models.AutoField(primary_key=True)
19     user = models.ForeignKey('User')
20     category = models.ForeignKey(UserMessageCategory, db_column='user_message_category_id')
21     txt = models.TextField()
22     class Meta:
23         db_table = u'user_message'
24
25 class User(models.Model):
26     id = models.AutoField(primary_key=True)
27     login = models.CharField(max_length=16, unique=True)
28     password_hash = models.CharField(max_length=75)
29     name = models.CharField(max_length=50)
30     email = models.EmailField()
31     father = models.ForeignKey('User')
32     creation_datetime = models.DateTimeField(auto_now_add=True)
33     phone = models.CharField(max_length=20, blank=True)
34     access_datetime = models.DateTimeField(blank=True, null=True)
35     class Meta:
36         db_table = u'user'
37         ordering = ('id',)
38
39     def __unicode__(self):
40         return self.login
41
42     def set_password(self, raw_password):
43         import random
44         algo = 'sha1'
45         salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
46         hsh = get_hexdigest(algo, salt, raw_password)
47         self.password_hash = '%s$%s$%s' % (algo, salt, hsh)
48         self.info('Password changed') # FIXME
49
50     def check_password(self, raw_password):
51         algo, salt, hsh = self.password_hash.split('$')
52         return hsh == get_hexdigest(algo, salt, raw_password)
53
54
55     def update_access_datetime(self):
56         self.access_datetime = datetime.utcnow()
57         self.save()
58
59     def get_and_delete_messages(self):
60         return None
61
62     def is_admin_by(self, user_id):
63         if self.id == user_id:
64             return True
65         if self.father_id is None:
66             return False
67         return self.father.is_admin_by(user_id)
68
69     def get_messages(self):
70         messages = UserMessage.objects.filter(user__id = self.id)
71         messages_dict = \
72             [ {'category': message.category, \
73                'txt': message.txt} \
74             for message in messages \
75             ]
76         messages.delete()
77         return messages_dict
78     
79     def info(self, message):
80         UserMessage(user_id = self.id, category_id=u'info', txt=html.escape(message)).save()
81
82     def error(self, message):
83         UserMessage(user_id = self.id, category_id=u'error', txt=html.escape(message)).save()
84
85     def check_sandbox_access(self, source_user=None):
86         SANDBOX_FLEET = 1
87         try:
88             FleetUser.objects.get(fleet = SANDBOX_FLEET, user = self)
89         except FleetUser.DoesNotExist:
90             fu = FleetUser()
91             fu.user_id = self.id
92             fu.fleet_id = SANDBOX_FLEET
93             fu.save()
94             if source_user:
95                 source_user.info("%s was granted access to 'sandbox' fleet" % self.login)
96
97
98 class Vessel(models.Model):
99     mmsi = models.IntegerField(primary_key=True)
100     name = models.CharField(max_length=20)
101     imo = models.IntegerField()
102     callsign = models.CharField(max_length=7)
103     type = models.IntegerField(default=0)
104     destination = models.CharField(max_length=20, blank=True, null=True)
105     updated = models.DateTimeField()
106     source = models.CharField(max_length=8)
107     dim_bow = models.IntegerField(default=0)
108     dim_stern = models.IntegerField(default=0)
109     dim_port = models.IntegerField(default=0)
110     dim_starboard = models.IntegerField(default=0)
111     eta = models.CharField(max_length=8, default='00002460') # format MMDDhhmm
112     class Meta:
113         db_table = u'vessel'
114     def __unicode__(self):
115         return unicode(self.mmsi) # FIXME
116     def get_last_nmea(self):
117         strmmsi = mmsi_to_strmmsi(self.mmsi)
118         return Nmea.new_from_lastinfo(strmmsi)
119
120
121 class Fleet(models.Model):
122     id = models.AutoField(primary_key=True)
123     name = models.CharField(max_length=50)
124     vessel = models.ManyToManyField(Vessel, through='FleetVessel')
125     description = models.TextField()
126     class Meta:
127         db_table = u'fleet'
128     def __unicode__(self):
129         return self.name
130     def vessel_count(self):
131         return FleetVessel.objects.filter(fleet=self.id).count()
132     def user_count(self):
133         return FleetUser.objects.filter(fleet=self.id).count()
134     def job_count(self):
135         if os.path.exists('/var/lib/ais/cron/fleets/%s.cron' % self.name):
136             return 1
137         else:
138             return 0
139
140 class FleetUser(models.Model):
141     id = models.AutoField(primary_key=True)
142     fleet = models.ForeignKey(Fleet) #, db_column='fleet_id', to_field='id')
143     user = models.ForeignKey(User)
144     class Meta:
145         db_table = u'fleet_user'
146
147 class FleetVessel(models.Model):
148     id = models.AutoField(primary_key=True)
149     fleet = models.ForeignKey(Fleet, db_column='fleet_id', to_field='id')
150     vessel = models.ForeignKey(Vessel, db_column='mmsi', to_field='mmsi')
151     class Meta:
152         db_table = u'fleet_vessel'
153     
154 ## manual input source
155 #class MiSource(models.Model):
156 #    id = models.IntegerField(primary_key=True)
157 #    userid = models.IntegerField()
158 #    name = models.TextField(unique=True)
159 #    class Meta:
160 #        db_table = u'mi_source'
161 #
162 ## manual input vessel
163 #class MiVessel(models.Model):
164 #    mmsi_txt = models.TextField(primary_key=True) # This field type is a guess.
165 #    class Meta:
166 #        db_table = u'mi_vessel'
167
168
169 # Plane plotter
170 #class Ppuser(models.Model):
171 #    usr = models.TextField(primary_key=True) # This field type is a guess.
172 #    lat = models.FloatField()
173 #    lon = models.FloatField()
174 #    class Meta:
175 #        db_table = u'ppuser'
176 #
177 #class Plane(models.Model):
178 #    flight = models.CharField(max_length=8)
179 #    reg = models.CharField(max_length=8)
180 #    ads = models.CharField(max_length=8)
181 #    type = models.CharField(max_length=4)
182 #    usr = models.TextField() # This field type is a guess.
183 #    updated = models.DateTimeField()
184 #    class Meta:
185 #        db_table = u'plane'
186
187
188
189 class News(models.Model):
190     id = models.AutoField(primary_key=True)
191     created = models.DateTimeField()
192     updated = models.DateTimeField()
193     title = models.TextField()
194     txt = models.TextField()
195     class Meta:
196         db_table = u'news'
197
198
199 class Job(models.Model):
200     def make_unique_job_id():
201         def make_id():
202             rnd = SystemRandom()
203             source = u'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
204             result = u''
205             for i in range(8):
206                 result += source[int(rnd.random()*len(source))]
207             return result
208         return make_id() # TODO check it's unique
209     
210     id = models.CharField(primary_key=True, max_length=8, default=make_unique_job_id)
211     user = models.ForeignKey(User)
212     queue_time = models.DateTimeField(auto_now_add=True)
213     start_time = models.DateTimeField(blank=True, null=True)
214     finish_time = models.DateTimeField(blank=True, null=True)
215     command = models.TextField()
216     friendly_filename = models.CharField(max_length=255)
217     pid = models.IntegerField(blank=True, null=True)
218     result = models.IntegerField(blank=True, null=True)
219     archive_time = models.DateTimeField(blank=True, null=True)
220
221     def nice_command(self):
222         if self.command.startswith('python -m'):
223             return self.command[len('python -m '):]
224         else:
225             return self.command
226
227     def queue_rank(self):
228         return Job.objects.filter(queue_time__lt=self.queue_time).filter(start_time__isnull=True).count() + 1
229     def process_time(self):
230         dt = self.finish_time - self.start_time
231         return nice_timedelta_str(dt)
232
233     class Meta:
234         db_table = u'job'
235         ordering = ('queue_time',)