This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/data/database.py
2013-10-09 23:00:34 -04:00

165 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 connect_db():
logger.debug('Connectin to database.')
db.connect()
def close_db(exc):
if not db.is_closed():
logger.debug('Disconnecting from database.')
db.close()
app.before_request(connect_db)
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):
code = CharField(default=random_string_generator(), unique=True, index=True)
user = ForeignKeyField(User, null=True)
repository = ForeignKeyField(Repository)
created = DateTimeField(default=datetime.now)
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')