162 lines
4.1 KiB
Python
162 lines
4.1 KiB
Python
import string
|
|
import logging
|
|
|
|
from random import SystemRandom
|
|
from datetime import datetime
|
|
from peewee import *
|
|
from peewee import create_model_tables
|
|
|
|
from app import app
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
db = app.config['DB_DRIVER'](app.config['DB_NAME'],
|
|
**app.config['DB_CONNECTION_ARGS'])
|
|
|
|
|
|
def close_db(exc):
|
|
if not db.is_closed():
|
|
logger.debug('Disconnecting from database.')
|
|
db.close()
|
|
|
|
|
|
app.teardown_request(close_db)
|
|
|
|
|
|
class BaseModel(Model):
|
|
class Meta:
|
|
database = db
|
|
|
|
|
|
class User(BaseModel):
|
|
username = CharField(unique=True, index=True)
|
|
password_hash = CharField(null=True)
|
|
email = CharField(unique=True, index=True)
|
|
verified = BooleanField(default=False)
|
|
stripe_id = CharField(index=True, null=True)
|
|
|
|
|
|
class LoginService(BaseModel):
|
|
name = CharField(unique=True, index=True)
|
|
|
|
|
|
class FederatedLogin(BaseModel):
|
|
user = ForeignKeyField(User, index=True)
|
|
service = ForeignKeyField(LoginService, index=True)
|
|
service_ident = CharField()
|
|
|
|
class Meta:
|
|
database = db
|
|
indexes = (
|
|
# create a unique index on service and the local service id
|
|
(('service', 'service_ident'), True),
|
|
|
|
# a user may only have one federated login per service
|
|
(('service', 'user'), True),
|
|
)
|
|
|
|
|
|
class Visibility(BaseModel):
|
|
name = CharField(index=True)
|
|
|
|
|
|
class Repository(BaseModel):
|
|
namespace = CharField()
|
|
name = CharField()
|
|
visibility = ForeignKeyField(Visibility)
|
|
description = TextField(null=True)
|
|
|
|
class Meta:
|
|
database = db
|
|
indexes = (
|
|
# create a unique index on namespace and name
|
|
(('namespace', 'name'), True),
|
|
)
|
|
|
|
|
|
class Role(BaseModel):
|
|
name = CharField(index=True)
|
|
|
|
|
|
class RepositoryPermission(BaseModel):
|
|
user = ForeignKeyField(User, index=True)
|
|
repository = ForeignKeyField(Repository, index=True)
|
|
role = ForeignKeyField(Role)
|
|
|
|
class Meta:
|
|
database = db
|
|
indexes = (
|
|
(('user', 'repository'), True),
|
|
)
|
|
|
|
|
|
def random_string_generator(length=16):
|
|
def random_string():
|
|
random = SystemRandom()
|
|
return ''.join([random.choice(string.ascii_uppercase + string.digits)
|
|
for x in range(length)])
|
|
return random_string
|
|
|
|
|
|
class AccessToken(BaseModel):
|
|
friendly_name = CharField(null=True)
|
|
code = CharField(default=random_string_generator(length=64), unique=True,
|
|
index=True)
|
|
repository = ForeignKeyField(Repository)
|
|
created = DateTimeField(default=datetime.now)
|
|
role = ForeignKeyField(Role)
|
|
temporary = BooleanField(default=True)
|
|
|
|
|
|
class EmailConfirmation(BaseModel):
|
|
code = CharField(default=random_string_generator(), unique=True, index=True)
|
|
user = ForeignKeyField(User)
|
|
pw_reset = BooleanField(default=False)
|
|
email_confirm = BooleanField(default=False)
|
|
created = DateTimeField(default=datetime.now)
|
|
|
|
|
|
class Image(BaseModel):
|
|
# This class is intentionally denormalized. Even though images are supposed
|
|
# to be globally unique we can't treat them as such for permissions and
|
|
# security reasons. So rather than Repository <-> Image being many to many
|
|
# each image now belongs to exactly one repository.
|
|
docker_image_id = CharField()
|
|
checksum = CharField(null=True)
|
|
created = DateTimeField(null=True)
|
|
comment = TextField(null=True)
|
|
repository = ForeignKeyField(Repository)
|
|
|
|
# '/' separated list of ancestory ids, e.g. /1/2/6/7/10/
|
|
ancestors = CharField(index=True, default='/', max_length=64535)
|
|
|
|
class Meta:
|
|
database = db
|
|
indexes = (
|
|
# we don't really want duplicates
|
|
(('repository', 'docker_image_id'), True),
|
|
)
|
|
|
|
|
|
class RepositoryTag(BaseModel):
|
|
name = CharField()
|
|
image = ForeignKeyField(Image)
|
|
repository = ForeignKeyField(Repository)
|
|
|
|
class Meta:
|
|
database = db
|
|
indexes = (
|
|
(('repository', 'name'), True),
|
|
)
|
|
|
|
|
|
def initialize_db():
|
|
create_model_tables([User, Repository, Image, AccessToken, Role,
|
|
RepositoryPermission, Visibility, RepositoryTag,
|
|
EmailConfirmation, FederatedLogin, LoginService])
|
|
Role.create(name='admin')
|
|
Role.create(name='write')
|
|
Role.create(name='read')
|
|
Visibility.create(name='public')
|
|
Visibility.create(name='private')
|
|
LoginService.create(name='github')
|