Jude's latest changes to syndicate models and admin
diff --git a/planetstack/syndicate/models.py b/planetstack/syndicate/models.py
index efc08c6..656e881 100644
--- a/planetstack/syndicate/models.py
+++ b/planetstack/syndicate/models.py
@@ -1,8 +1,9 @@
-from core.models import User,Site,Service,SingletonModel,PlCoreBase
+from core.models import User,Site,Service,SingletonModel,PlCoreBase,Slice
import os
from django.db import models
from django.forms.models import model_to_dict
from bitfield import BitField
+from django.core.exceptions import ValidationError
# Create your models here.
@@ -14,51 +15,79 @@
def __unicode__(self): return u'Syndicate Service'
-class SyndicateUser(models.Model):
- user = models.ForeignKey(User)
- is_admin = models.BooleanField(default=False, help_text="Indicates this user has Administrative purposes for the Syndicate Service")
- max_volumes = models.PositiveIntegerField(help_text="Maximum number of Volumes this user may create.", default=1)
- max_UGs = models.PositiveIntegerField(help_text="Maximum number of User Gateways this user may create.", default=500)
- max_RGs = models.PositiveIntegerField(help_text="Maximum number of Replica Gateways this user may create.", default=500)
- max_AGs = models.PositiveIntegerField(help_text="Maximum number of Aquisition Gateways this user may create.", default=10)
-
- def __unicode__(self): return self.user.email
-
-class Volume(models.Model):
+class SyndicatePrincipal(PlCoreBase):
+ class Meta:
+ app_label = "syndicate"
+
+ # for now, this is a user email address
+ principal_id = models.TextField()
+ public_key_pem = models.TextField()
+ sealed_private_key = models.TextField()
+
+ def __unicode__self(self): return "%s" % self.principal_id
+
+
+class Volume(PlCoreBase):
+ class Meta:
+ app_label = "syndicate"
+
name = models.CharField(max_length=64, help_text="Human-readable, searchable name of the Volume")
- owner_id = models.ForeignKey(SyndicateUser, verbose_name='Owner')
+
+ owner_id = models.ForeignKey(User, verbose_name='Owner')
+
description = models.TextField(null=True, blank=True,max_length=130, help_text="Human-readable description of what this Volume is used for.")
blocksize = models.PositiveIntegerField(help_text="Number of bytes per block.")
private = models.BooleanField(default=True, help_text="Indicates if the Volume is visible to users other than the Volume Owner and Syndicate Administrators.")
- archive = models.BooleanField(default=True, help_text="Indicates if this Volume is read-only, and only an Aquisition Gateway owned by the Volume owner (or Syndicate admin) can write to it.")
- metadata_public_key = models.TextField(null=True, blank=True, max_length=1024, help_text="Public key Gateways will use to verify the authenticity of metadata from this Volume")
- metadata_private_key = models.TextField(null=True, blank=True, max_length=1024, help_text="Private key the Volume should use to sign metadata served to Gateways")
- api_public_key = models.TextField(null=True, blank=True, max_length=1024, help_text="Public key used to verify writes to these fields from Volume owner")
+ archive = models.BooleanField(default=False, help_text="Indicates if this Volume is read-only, and only an Aquisition Gateway owned by the Volume owner (or Syndicate admin) can write to it.")
- file_quota = models.IntegerField(help_text='Maximum number of files and directories allowed in this Volume (-1 means "unlimited")')
-
- default_gateway_caps = BitField(flags=('GATEWAY_CAP_READ_DATA','GATEWAY_CAP_READ_METADATA', 'GATEWAY_CAP_WRITE_DATA', 'GATEWAY_CAP_WRITE_METADATA', 'GATEWAY_CAP_COORDINATE'), verbose_name='Default Gateway Capabilities')
- #default_gateway_caps = models.PositiveIntegerField(verbose_name='Default Gateway Capabilities')
- #default_gateway_caps2 = models.CharField(max_length=32,null=True,default = "readonly", verbose_name='Default Gateway Capabilities')
+ CAP_READ_DATA = 1
+ CAP_WRITE_DATA = 2
+ CAP_HOST_DATA = 4
+
+ # NOTE: preserve order of capabilities here...
+ default_gateway_caps = BitField(flags=("read data", "write data", "host files"), verbose_name='Default User Capabilities')
def __unicode__(self): return self.name
-class VolumeAccessRight(models.Model):
- owner_id = models.ForeignKey(SyndicateUser, verbose_name='user')
+
+class VolumeAccessRight(PlCoreBase):
+ class Meta:
+ app_label = "syndicate"
+
+ owner_id = models.ForeignKey(User, verbose_name='user')
+
volume = models.ForeignKey(Volume)
- gateway_caps = BitField(flags=('GATEWAY_CAP_READ_DATA','GATEWAY_CAP_READ_METADATA', 'GATEWAY_CAP_WRITE_DATA', 'GATEWAY_CAP_WRITE_METADATA', 'GATEWAY_CAP_COORDINATE'), verbose_name='Gateway Capabilities')
- #gateway_caps = models.PositiveIntegerField(verbose_name='Gateway Capabilities')
- #gateway_caps2 = models.CharField(max_length=32, default='readonly',null=True,verbose_name='Default Gateway Capabilities')
+ gateway_caps = BitField(flags=("read data", "write data", "host files"), verbose_name="User Capabilities")
- def __unicode__(self): return self.owner_id.user.email
+ def __unicode__(self): return "%s-%s" % (self.owner_id.email, self.volume.name)
-class VolumeAccessRequest(models.Model):
- owner_id = models.ForeignKey(SyndicateUser, verbose_name='user')
- volume = models.ForeignKey(Volume)
- message = models.TextField(null=True, blank=True, max_length=1024, help_text="Description of why the user wants access to the volume.")
- gateway_caps = BitField(flags=('GATEWAY_CAP_READ_DATA','GATEWAY_CAP_READ_METADATA', 'GATEWAY_CAP_WRITE_DATA', 'GATEWAY_CAP_WRITE_METADATA', 'GATEWAY_CAP_COORDINATE'), verbose_name='Gateway Capabilities')
- #gateway_caps = models.PositiveIntegerField(verbose_name='Gateway Capabilities')
- #gateway_caps2 = models.CharField(max_length=32,default='readonly',null=True,verbose_name='Default Gateway Capabilities')
- def __unicode__(self): return self.owner_id.user.email
+class VolumeSlice(PlCoreBase):
+ class Meta:
+ app_label = "syndicate"
+
+ volume_id = models.ForeignKey(Volume, verbose_name="Volume")
+ slice_id = models.ForeignKey(Slice, verbose_name="Slice")
+ gateway_caps = BitField(flags=("read data", "write data", "host files"), verbose_name="Slice Capabilities")
+
+ peer_portnum = models.PositiveIntegerField(help_text="User Gateway port", verbose_name="Client peer-to-peer cache port")
+ replicate_portnum = models.PositiveIntegerField(help_text="Replica Gateway port", verbose_name="Replication service port")
+
+ credentials_blob = models.TextField(null=True, blank=True, help_text="Encrypted slice credentials")
+
+ def __unicode__(self): return "%s-%s" % (self.volume_id.name, self.slice_id.name)
+
+ def clean(self):
+ """
+ Verify that our fields are in order:
+ * peer_portnum and replicate_portnum have to be valid port numbers between 1025 and 65534
+ * peer_portnum and replicate_portnum cannot be changed once set.
+ """
+
+ if self.peer_portnum < 1025 or self.peer_portnum > 65534:
+ raise ValidationError( "Client peer-to-peer cache port number must be between 1025 and 65534" )
+
+ if self.replicate_portnum < 1025 or self.replicate_portnum > 65534:
+ raise ValidationError( "Replication service port number must be between 1025 and 65534" )
+