Initial Cleanup
This commit is contained in:
parent
70d3cd8b6a
commit
025202df3f
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@
|
||||
|
||||
config.py
|
||||
|
||||
.ropeproject/*
|
||||
|
@ -1,51 +1,43 @@
|
||||
from eve import Eve
|
||||
from eve.auth import TokenAuth
|
||||
|
||||
# import config
|
||||
# from flask import Flask, Blueprint
|
||||
# from flask.ext.mail import Mail
|
||||
# from flask.ext.sqlalchemy import SQLAlchemy
|
||||
# from flask.ext.thumbnails import Thumbnail
|
||||
# from flask.ext.assets import Environment, Bundle
|
||||
|
||||
# Initialize the Flask all object
|
||||
import random
|
||||
import string
|
||||
|
||||
from eve.io.mongo import Validator
|
||||
|
||||
class ValidateCustomFields(Validator):
|
||||
def _validate_validcf(self, validcf, field, value):
|
||||
if validcf:
|
||||
print self.document['node_type']
|
||||
if value == 'hi':
|
||||
return True
|
||||
else:
|
||||
self._error(field, "Must be hi")
|
||||
def _validate_valid_properties(self, valid_properties, field, value):
|
||||
node_types = app.data.driver.db['ntypes']
|
||||
lookup = {}
|
||||
lookup['_id'] = self.document['node_type']
|
||||
node_type = node_types.find_one(lookup)
|
||||
|
||||
v = Validator(node_type['dyn_schema'])
|
||||
val = v.validate(value)
|
||||
if val:
|
||||
return True
|
||||
else:
|
||||
self._error(field, "Must be hi")
|
||||
|
||||
|
||||
app = Eve(validator=ValidateCustomFields)
|
||||
class RolesAuth(TokenAuth):
|
||||
def check_auth(self, token, allowed_roles, resource, method):
|
||||
accounts = app.data.driver.db['users']
|
||||
lookup = {'token': token}
|
||||
if allowed_roles:
|
||||
lookup['role'] = {'$in': allowed_roles}
|
||||
account = accounts.find_one(lookup)
|
||||
return account
|
||||
|
||||
|
||||
# Filemanager used by Flask-Admin extension
|
||||
# filemanager = Blueprint('filemanager', __name__, static_folder='static/files')
|
||||
def add_token(documents):
|
||||
# Don't use this in production:
|
||||
# You should at least make sure that the token is unique.
|
||||
for document in documents:
|
||||
document["token"] = (''.join(random.choice(string.ascii_uppercase)
|
||||
for x in range(10)))
|
||||
|
||||
# # Choose the configuration to load
|
||||
# app.config.from_object(config.Development)
|
||||
app = Eve(validator=ValidateCustomFields, auth=RolesAuth)
|
||||
app.on_insert_users += add_token
|
||||
|
||||
# # Initialized the available extensions
|
||||
# mail = Mail(app)
|
||||
# db = SQLAlchemy(app)
|
||||
# thumb = Thumbnail(app)
|
||||
# assets = Environment(app)
|
||||
|
||||
# # Import controllers
|
||||
# from application.modules.nodes import node_types
|
||||
# from application.modules.nodes import nodes
|
||||
# from application.modules.main import homepage
|
||||
# from application.modules.shots import shots
|
||||
# from application.modules.projects import projects
|
||||
|
||||
# # Register blueprints for the imported controllers
|
||||
# app.register_blueprint(filemanager)
|
||||
# app.register_blueprint(shots, url_prefix='/shots')
|
||||
# app.register_blueprint(projects, url_prefix='/projects')
|
||||
# app.register_blueprint(node_types, url_prefix='/node-types')
|
||||
# app.register_blueprint(nodes, url_prefix='/nodes')
|
||||
|
@ -1,7 +0,0 @@
|
||||
from application import app
|
||||
from application.modules.shots import index
|
||||
|
||||
@app.route("/")
|
||||
def homepage():
|
||||
"""Very minimal setup that returns the shot index view"""
|
||||
return index()
|
@ -1,167 +0,0 @@
|
||||
from flask import abort
|
||||
from flask import Blueprint
|
||||
from flask import jsonify
|
||||
from flask import render_template
|
||||
from flask import redirect
|
||||
from flask import request
|
||||
from flask import flash
|
||||
from flask import url_for
|
||||
|
||||
from application import db
|
||||
|
||||
from application.modules.nodes.models import Node, NodeType
|
||||
from application.modules.nodes.forms import NodeTypeForm
|
||||
from application.modules.nodes.forms import CustomFieldForm
|
||||
from application.modules.nodes.forms import get_node_form
|
||||
from application.modules.nodes.forms import process_node_form
|
||||
|
||||
|
||||
# Name of the Blueprint
|
||||
node_types = Blueprint('node_types', __name__)
|
||||
nodes = Blueprint('nodes', __name__)
|
||||
|
||||
@node_types.route("/")
|
||||
def index():
|
||||
"""Display the node types
|
||||
"""
|
||||
node_types = [t for t in NodeType.query.all()]
|
||||
|
||||
return render_template('node_types/index.html',
|
||||
title='node_types',
|
||||
node_types=node_types)
|
||||
|
||||
shots = []
|
||||
for shot in Node.query.\
|
||||
join(NodeType).\
|
||||
filter(NodeType.url == 'shot'):
|
||||
status = None
|
||||
if shot.status:
|
||||
status = shot.status.name
|
||||
shots.append(dict(
|
||||
id=shot.id,
|
||||
name=shot.name,
|
||||
description=shot.description,
|
||||
duration=shot.node_shot[0].duration,
|
||||
status=status,
|
||||
notes=shot.node_shot[0].notes))
|
||||
return render_template('shots/index.html',
|
||||
title='shots',
|
||||
shots=shots)
|
||||
|
||||
|
||||
@node_types.route("/add", methods=['GET', 'POST'])
|
||||
def add():
|
||||
form = NodeTypeForm()
|
||||
|
||||
if form.validate_on_submit():
|
||||
node_type = NodeType(
|
||||
name=form.name.data,
|
||||
description=form.description.data,
|
||||
url=form.url.data)
|
||||
|
||||
db.session.add(node_type)
|
||||
db.session.commit()
|
||||
|
||||
return redirect(url_for('node_types.index'))
|
||||
return render_template('node_types/add.html', form=form)
|
||||
|
||||
|
||||
@node_types.route("/<int:node_type_id>/edit", methods=['GET', 'POST'])
|
||||
def edit(node_type_id):
|
||||
node_type = NodeType.query.get_or_404(node_type_id)
|
||||
|
||||
form = NodeTypeForm(obj=node_type)
|
||||
|
||||
if form.validate_on_submit():
|
||||
node_type.name = form.name.data
|
||||
node_type.description = form.description.data
|
||||
node_type.url = form.url.data
|
||||
# Processing custom fields
|
||||
for field in form.custom_fields:
|
||||
print field.data['id']
|
||||
|
||||
db.session.commit()
|
||||
else:
|
||||
print form.errors
|
||||
|
||||
|
||||
# if form.validate_on_submit():
|
||||
# node_type = NodeType(
|
||||
# name=form.name.data,
|
||||
# description=form.description.data,
|
||||
# url=form.url.data)
|
||||
|
||||
# db.session.add(node_type)
|
||||
# db.session.commit()
|
||||
|
||||
# return redirect(url_for('node_types.index'))
|
||||
return render_template('node_types/edit.html',
|
||||
node_type=node_type,
|
||||
form=form)
|
||||
|
||||
|
||||
|
||||
@nodes.route("/", methods=['GET', 'POST'])
|
||||
def index():
|
||||
"""Generic function to list all nodes
|
||||
"""
|
||||
nodes = Node.query.all()
|
||||
return render_template('nodes/index.html',
|
||||
nodes=nodes)
|
||||
|
||||
|
||||
@nodes.route("/<node_type>/add", methods=['GET', 'POST'])
|
||||
def add(node_type):
|
||||
"""Generic function to add a node of any type
|
||||
"""
|
||||
form = get_node_form(node_type)
|
||||
if form.validate_on_submit():
|
||||
if process_node_form(form):
|
||||
return redirect('/')
|
||||
else:
|
||||
print form.errors
|
||||
return render_template('nodes/add.html',
|
||||
node_type=node_type,
|
||||
form=form)
|
||||
|
||||
|
||||
@nodes.route("/<int:node_id>/edit", methods=['GET', 'POST'])
|
||||
def edit(node_id):
|
||||
"""Generic node editing form
|
||||
"""
|
||||
node = Node.query.get_or_404(node_id)
|
||||
form = get_node_form(node.node_type.url)
|
||||
|
||||
if form.validate_on_submit():
|
||||
if process_node_form(form, node_id):
|
||||
return redirect(url_for('node.edit', node_id=node_id))
|
||||
|
||||
form.name.data = node.name
|
||||
form.description.data = node.description
|
||||
|
||||
# We populate the form, basing ourselves on the default node properties
|
||||
for node_property in node.properties:
|
||||
for field in form:
|
||||
if field.name == node_property.custom_field.name_url:
|
||||
value = node_property.value
|
||||
# We cast values into the right type
|
||||
if node_property.custom_field.field_type == 'integer':
|
||||
value = int(value)
|
||||
if node_property.custom_field.field_type == 'select':
|
||||
value = int(value)
|
||||
field.data = value
|
||||
|
||||
|
||||
return render_template('nodes/edit.html',
|
||||
node=node,
|
||||
form=form)
|
||||
|
||||
|
||||
@nodes.route("/<int:node_id>/delete", methods=['GET', 'POST'])
|
||||
def delete(node_id):
|
||||
"""Generic node deletion
|
||||
"""
|
||||
node = Node.query.get_or_404(node_id)
|
||||
db.session.delete(node)
|
||||
db.session.commit()
|
||||
return 'ok'
|
@ -1,160 +0,0 @@
|
||||
from flask_wtf import Form
|
||||
from wtforms import TextField
|
||||
from wtforms import BooleanField
|
||||
from wtforms import SelectField
|
||||
from wtforms import TextAreaField
|
||||
from wtforms import IntegerField
|
||||
from wtforms import HiddenField
|
||||
from wtforms import FieldList
|
||||
from wtforms import FormField
|
||||
from wtforms import Form as BasicForm
|
||||
|
||||
from application.modules.nodes.models import CustomFields
|
||||
from wtforms.validators import DataRequired
|
||||
|
||||
from application import db
|
||||
|
||||
from application.modules.nodes.models import Node, NodeType, NodeProperties
|
||||
|
||||
class CustomFieldForm(BasicForm):
|
||||
id = HiddenField()
|
||||
field_type = TextField('Field Type', validators=[DataRequired()])
|
||||
name = TextField('Name', validators=[DataRequired()])
|
||||
name_url = TextField('Url', validators=[DataRequired()])
|
||||
description = TextAreaField('Description')
|
||||
is_required = BooleanField('Is extended')
|
||||
def __init__(self, csrf_enabled=False, *args, **kwargs):
|
||||
super(CustomFieldForm, self).__init__(csrf_enabled=False, *args, **kwargs)
|
||||
|
||||
class ModelFieldList(FieldList):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.model = kwargs.pop("model", None)
|
||||
super(ModelFieldList, self).__init__(*args, **kwargs)
|
||||
if not self.model:
|
||||
raise ValueError("ModelFieldList requires model to be set")
|
||||
|
||||
def populate_obj(self, obj, name):
|
||||
while len(getattr(obj, name)) < len(self.entries):
|
||||
newModel = self.model()
|
||||
db.session.add(newModel)
|
||||
getattr(obj, name).append(newModel)
|
||||
while len(getattr(obj, name)) > len(self.entries):
|
||||
db.session.delete(getattr(obj, name).pop())
|
||||
super(ModelFieldList, self).populate_obj(obj, name)
|
||||
|
||||
class ChildInline(Form):
|
||||
title = TextField('Title',)
|
||||
|
||||
class NodeTypeForm(Form):
|
||||
name = TextField('Name', validators=[DataRequired()])
|
||||
url = TextField('Url', validators=[DataRequired()])
|
||||
description = TextAreaField('Description', validators=[DataRequired()])
|
||||
is_extended = BooleanField('Is extended')
|
||||
custom_fields = ModelFieldList(FormField(CustomFieldForm), model=CustomFields)
|
||||
|
||||
|
||||
class IMForm(Form):
|
||||
protocol = SelectField(choices=[('aim', 'AIM'), ('msn', 'MSN')])
|
||||
username = TextField()
|
||||
|
||||
class ContactForm(Form):
|
||||
first_name = TextField()
|
||||
last_name = TextField()
|
||||
im_accounts = FieldList(BooleanField('Is extended'),)
|
||||
|
||||
|
||||
def get_node_form(node_type):
|
||||
node_type = NodeType.query.filter_by(url=node_type).first()
|
||||
class ProceduralForm(Form):
|
||||
pass
|
||||
|
||||
setattr(ProceduralForm,
|
||||
'name',
|
||||
TextField('Name', validators=[DataRequired()]))
|
||||
setattr(ProceduralForm,
|
||||
'url',
|
||||
TextField('Url'))
|
||||
setattr(ProceduralForm,
|
||||
'description',
|
||||
TextAreaField('Description', validators=[DataRequired()]))
|
||||
setattr(ProceduralForm,
|
||||
'node_type_id',
|
||||
HiddenField(default=node_type.id))
|
||||
|
||||
for custom_field in CustomFields.query\
|
||||
.join(NodeType)\
|
||||
.filter(NodeType.url == node_type.url):
|
||||
|
||||
if custom_field.field_type == 'text':
|
||||
field_properties = TextAreaField(custom_field.name,
|
||||
validators=[DataRequired()])
|
||||
elif custom_field.field_type == 'string':
|
||||
field_properties = TextField(custom_field.name,
|
||||
validators=[DataRequired()])
|
||||
elif custom_field.field_type == 'integer':
|
||||
field_properties = IntegerField(custom_field.name,
|
||||
validators=[DataRequired()])
|
||||
elif custom_field.field_type == 'select':
|
||||
options = Node.query\
|
||||
.join(NodeType)\
|
||||
.filter(NodeType.url==custom_field.name_url)\
|
||||
.all()
|
||||
field_properties = SelectField(custom_field.name,
|
||||
coerce=int,
|
||||
choices=[(option.id, option.name) for option in options] )
|
||||
|
||||
setattr(ProceduralForm, custom_field.name_url, field_properties)
|
||||
|
||||
return ProceduralForm()
|
||||
|
||||
|
||||
def process_node_form(form, node_id=None):
|
||||
"""Generic function used to process new nodes, as well as edits
|
||||
"""
|
||||
if form.validate_on_submit():
|
||||
node_type = NodeType.query.get(form.node_type_id.data)
|
||||
if node_id:
|
||||
node = Node.query.get(node_id)
|
||||
node.name = form.name.data
|
||||
node.description = form.description.data
|
||||
else:
|
||||
node = Node(
|
||||
name=form.name.data,
|
||||
description=form.description.data,
|
||||
node_type_id=form.node_type_id.data)
|
||||
db.session.add(node)
|
||||
db.session.commit()
|
||||
|
||||
for custom_field in CustomFields.query\
|
||||
.join(NodeType)\
|
||||
.filter(NodeType.url == node_type.url):
|
||||
|
||||
for field in form:
|
||||
if field.name == custom_field.name_url:
|
||||
if node_id:
|
||||
# Query for the indivitual property
|
||||
# TODO: collect all properties and loop through them
|
||||
node_property = NodeProperties.query\
|
||||
.filter_by(node_id=node_id)\
|
||||
.filter_by(custom_field_id=custom_field.id)\
|
||||
.first()
|
||||
if node_property:
|
||||
# Update the value of the property
|
||||
node_property.value = field.data
|
||||
else:
|
||||
# If the property is missing we add it
|
||||
node_property = NodeProperties(
|
||||
node_id=node.id,
|
||||
custom_field_id=custom_field.id,
|
||||
value=field.data)
|
||||
db.session.add(node_property)
|
||||
else:
|
||||
node_property = NodeProperties(
|
||||
node_id=node.id,
|
||||
custom_field_id=custom_field.id,
|
||||
value=field.data)
|
||||
db.session.add(node_property)
|
||||
db.session.commit()
|
||||
return True
|
||||
else:
|
||||
return False
|
@ -1,95 +0,0 @@
|
||||
from application import app
|
||||
from application import db
|
||||
|
||||
import os
|
||||
import os.path as op
|
||||
import datetime
|
||||
|
||||
import hashlib
|
||||
import time
|
||||
|
||||
from werkzeug import secure_filename
|
||||
|
||||
|
||||
def prefix_name(obj, file_data):
|
||||
# Collect name and extension
|
||||
parts = op.splitext(file_data.filename)
|
||||
# Get current time (for unique hash)
|
||||
timestamp = str(round(time.time()))
|
||||
# Has filename only (not extension)
|
||||
file_name = secure_filename(timestamp + '%s' % parts[0])
|
||||
# Put them together
|
||||
full_name = hashlib.md5(file_name).hexdigest() + parts[1]
|
||||
return full_name
|
||||
|
||||
|
||||
# Create directory for file fields to use
|
||||
file_path = op.join(op.dirname(__file__), 'static/files',)
|
||||
try:
|
||||
os.mkdir(file_path)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
class NodeType(db.Model):
|
||||
id = db.Column(db.Integer, primary_key = True)
|
||||
name = db.Column(db.String(120), nullable=False)
|
||||
description = db.Column(db.Text)
|
||||
url = db.Column(db.String(120), nullable=False)
|
||||
|
||||
custom_fields = db.relationship('CustomFields', backref='NodeType',
|
||||
cascade="all, delete, delete-orphan")
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Node(db.Model):
|
||||
id = db.Column(db.Integer, primary_key = True)
|
||||
name = db.Column(db.String(120), nullable=False)
|
||||
url = db.Column(db.String(120))
|
||||
description = db.Column(db.Text)
|
||||
main_picture = db.Column(db.String(80))
|
||||
order = db.Column(db.Integer)
|
||||
creation_date = db.Column(db.DateTime(), default=datetime.datetime.now)
|
||||
edit_date = db.Column(db.DateTime())
|
||||
|
||||
parent_id = db.Column(db.Integer, db.ForeignKey('node.id'))
|
||||
parent = db.relationship('Node', remote_side=[id])
|
||||
|
||||
node_type_id = db.Column(db.Integer(), db.ForeignKey(NodeType.id))
|
||||
node_type = db.relationship(NodeType, backref='Node')
|
||||
|
||||
properties = db.relationship('NodeProperties', backref='Node',
|
||||
cascade="all, delete, delete-orphan")
|
||||
|
||||
def get_property(self, name):
|
||||
for p in self.properties:
|
||||
if p.custom_field.name_url == name:
|
||||
return p
|
||||
print 'p'
|
||||
return None
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class CustomFields(db.Model):
|
||||
id = db.Column(db.Integer, primary_key = True)
|
||||
node_type_id = db.Column(db.Integer(), db.ForeignKey(NodeType.id))
|
||||
|
||||
field_type = db.Column(db.String(128))
|
||||
order = db.Column(db.Integer())
|
||||
name = db.Column(db.String(128))
|
||||
name_url = db.Column(db.String(128))
|
||||
description = db.Column(db.Text())
|
||||
|
||||
|
||||
class NodeProperties(db.Model):
|
||||
id = db.Column(db.Integer, primary_key = True)
|
||||
node_id = db.Column(db.Integer(), db.ForeignKey(Node.id))
|
||||
|
||||
custom_field_id = db.Column(db.Integer(), db.ForeignKey(CustomFields.id))
|
||||
custom_field = db.relationship(CustomFields, backref='NodeProperties')
|
||||
|
||||
value = db.Column(db.Text())
|
@ -1,30 +0,0 @@
|
||||
from flask import (abort,
|
||||
Blueprint,
|
||||
jsonify,
|
||||
render_template,
|
||||
redirect,
|
||||
request)
|
||||
|
||||
from flask.ext.thumbnails import Thumbnail
|
||||
from flask.ext.sqlalchemy import SQLAlchemy
|
||||
from sqlalchemy.orm import aliased
|
||||
|
||||
from application.modules.shots import Node
|
||||
from application.modules.shots import NodeType
|
||||
|
||||
# Name of the Blueprint
|
||||
projects = Blueprint('projects', __name__)
|
||||
|
||||
@projects.route("/")
|
||||
def index():
|
||||
projects = {}
|
||||
for project in Node.query.\
|
||||
join(NodeType).\
|
||||
filter(NodeType.url == 'project'):
|
||||
status = None
|
||||
if project.status:
|
||||
status = project.status.name
|
||||
projects[project.id] = dict(
|
||||
name=project.name,
|
||||
status=status)
|
||||
return jsonify(projects=projects)
|
@ -1,111 +0,0 @@
|
||||
from flask import (abort,
|
||||
Blueprint,
|
||||
jsonify,
|
||||
render_template,
|
||||
redirect,
|
||||
request,
|
||||
flash)
|
||||
|
||||
from flask.ext.thumbnails import Thumbnail
|
||||
from flask.ext.sqlalchemy import SQLAlchemy
|
||||
from sqlalchemy.orm import aliased
|
||||
|
||||
from application import db
|
||||
|
||||
from application.modules.shots.forms import ShotForm
|
||||
from application.modules.nodes.models import Node, NodeType, NodeProperties
|
||||
from application.modules.shots.models import NodeShot
|
||||
|
||||
|
||||
# Name of the Blueprint
|
||||
shots = Blueprint('shots', __name__)
|
||||
|
||||
@shots.route("/")
|
||||
def index():
|
||||
shots = []
|
||||
|
||||
for shot in Node.query.\
|
||||
join(NodeType).\
|
||||
filter(NodeType.url == 'shot'):
|
||||
status = None
|
||||
# if shot.status:
|
||||
# status = shot.status.name
|
||||
s = dict(
|
||||
id=shot.id,
|
||||
name=shot.name,
|
||||
description=shot.description)
|
||||
for node_property in shot.properties:
|
||||
s[node_property.custom_field.name_url] = node_property.value
|
||||
shots.append(s)
|
||||
return render_template('shots/index.html',
|
||||
title='shots',
|
||||
shots=shots)
|
||||
|
||||
|
||||
@shots.route("/view/<int:shot_id>")
|
||||
def view(shot_id):
|
||||
shot = Node.query.get(shot_id)
|
||||
if shot and shot.node_type.url == 'shot':
|
||||
return render_template('shots/view.html',
|
||||
title='shots',
|
||||
shot=shot,
|
||||
notes=shot.get_property('notes'))
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
||||
@shots.route("/add", methods=('GET', 'POST'))
|
||||
def add():
|
||||
form = ShotForm()
|
||||
|
||||
if form.validate_on_submit():
|
||||
shot_type = NodeType.query.filter_by(url='shot').first()
|
||||
shot = Node(
|
||||
name=form.name.data,
|
||||
description=form.description.data,
|
||||
node_type_id=shot_type.id,
|
||||
status_id=form.status_id.data)
|
||||
# Create entry in the attached node table
|
||||
shot.node_shot = [NodeShot(
|
||||
duration=form.duration.data,
|
||||
notes=form.notes.data)]
|
||||
|
||||
db.session.add(shot)
|
||||
db.session.commit()
|
||||
return redirect('/')
|
||||
return render_template('shots/add.html', form=form)
|
||||
|
||||
|
||||
@shots.route("/edit/<int:shot_id>", methods=('GET', 'POST'))
|
||||
def edit(shot_id):
|
||||
shot = Node.query.get(shot_id)
|
||||
|
||||
form = ShotForm(
|
||||
name=shot.name,
|
||||
description=shot.description,
|
||||
duration=shot.node_shot[0].duration,
|
||||
note=shot.node_shot[0].notes)
|
||||
|
||||
if form.validate_on_submit():
|
||||
shot.name = form.name.data
|
||||
shot.description = form.description.data
|
||||
shot.node_shot[0].duration = form.duration.data
|
||||
shot.status_id = form.status_id.data
|
||||
shot.node_shot[0].notes = form.notes.data
|
||||
db.session.commit()
|
||||
return redirect('/')
|
||||
return render_template(
|
||||
'shots/edit.html',
|
||||
form=form,
|
||||
shot_id=shot_id)
|
||||
|
||||
|
||||
@shots.route("/delete/<int:shot_id>")
|
||||
def delete(shot_id):
|
||||
shot = Node.query.get(shot_id)
|
||||
if shot:
|
||||
db.session.delete(shot)
|
||||
db.session.commit()
|
||||
return redirect('/')
|
||||
else:
|
||||
abort(404)
|
@ -1,24 +0,0 @@
|
||||
from flask_wtf import Form
|
||||
from wtforms import TextField
|
||||
from wtforms import BooleanField
|
||||
from wtforms import SelectField
|
||||
from wtforms import TextAreaField
|
||||
from wtforms import IntegerField
|
||||
|
||||
from wtforms.validators import DataRequired
|
||||
|
||||
from application.modules.nodes.models import Node, NodeType
|
||||
|
||||
class ShotForm(Form):
|
||||
statuses = Node.query\
|
||||
.join(NodeType)\
|
||||
.filter(NodeType.url == 'shot_status')\
|
||||
.all()
|
||||
|
||||
name = TextField('Shot Name', validators=[DataRequired()])
|
||||
description = TextAreaField('Description', validators=[DataRequired()])
|
||||
status_id = SelectField('Status',
|
||||
coerce=int,
|
||||
choices=[(status.id, status.name) for status in statuses])
|
||||
duration = IntegerField('Duration')
|
||||
notes = TextAreaField('Notes')
|
@ -1,53 +0,0 @@
|
||||
from application import app
|
||||
from application import db
|
||||
|
||||
from application.modules.nodes.models import Node
|
||||
|
||||
class NodeShot(db.Model):
|
||||
"""docstring for NodeShot"""
|
||||
id = db.Column(db.Integer, primary_key = True)
|
||||
duration = db.Column(db.Integer, nullable=False)
|
||||
notes = db.Column(db.Text)
|
||||
|
||||
node_id = db.Column(db.Integer, db.ForeignKey(Node.id))
|
||||
node = db.relationship(Node, backref='node_shot', uselist=False)
|
||||
|
||||
|
||||
|
||||
# Create Many to Many table
|
||||
"""
|
||||
assets_tags_table = db.Table('assets_tags', db.Model.metadata,
|
||||
db.Column('asset_id', db.Integer, db.ForeignKey('asset.id')),
|
||||
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'))
|
||||
)
|
||||
"""
|
||||
|
||||
# class Asset(db.Model):
|
||||
# id = db.Column(db.Integer, primary_key=True)
|
||||
# name = db.Column(db.String(120), nullable=False)
|
||||
# description = db.Column(db.Text, nullable=False)
|
||||
# link = db.Column(db.String(512))
|
||||
# picture = db.Column(db.String(80))
|
||||
# size = db.Column(db.String(7))
|
||||
# format = db.Column(db.String(15))
|
||||
# duration = db.Column(db.String(15))
|
||||
|
||||
# nodes = db.relationship('Node', secondary=nodes_assets_table)
|
||||
|
||||
# #tags = db.relationship('Tag', secondary=assets_tags_table)
|
||||
|
||||
# def __str__(self):
|
||||
# return self.name
|
||||
|
||||
"""
|
||||
|
||||
class Tag(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.Unicode(64))
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
"""
|
||||
|
||||
|
@ -1,102 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Attract</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
<link href="{{ url_for('static', filename='assets/css/bootstrap.min.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='assets/css/chosen.min.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='assets/css/bootstrap-markdown.min.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='assets/css/dataTables.bootstrap.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='assets/css/attract.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static', filename='assets/css/bootstrap-colorpicker.min.css') }}" rel="stylesheet">
|
||||
|
||||
<link rel="shortcut icon" href="{{ url_for('static', filename='assets/ico/favicon.png') }}">
|
||||
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="{{ url_for('static', filename='assets/ico/apple-touch-icon-144-precomposed.png') }}">
|
||||
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="{{ url_for('static', filename='assets/ico/apple-touch-icon-114-precomposed.png') }}">
|
||||
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="{{ url_for('static', filename='assets/ico/apple-touch-icon-72-precomposed.png') }}">
|
||||
<link rel="apple-touch-icon-precomposed" href="{{ url_for('static', filename='assets/ico/apple-touch-icon-57-precomposed.png') }}">
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button data-target=".navbar-collapse" data-toggle="collapse" class="navbar-toggle" type="button">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a href="/" class="navbar-brand">Attract</a>
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
|
||||
<li id="fat-menu" class="dropdown">
|
||||
<a href="#" id="drop3" class="dropdown-toggle" data-toggle="dropdown">User <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu" role="menu" aria-labelledby="drop3">
|
||||
<li><a role="menuitem" tabindex="-1" href="">Tasks</a></li>
|
||||
<li><a role="menuitem" tabindex="-1" href="">Profile</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a role="menuitem" tabindex="-1" href="{{url_for('node_types.index')}}">Node Types</a></li>
|
||||
<li><a role="menuitem" tabindex="-1" href="{{url_for('nodes.index')}}">All Nodes</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a role="menuitem" tabindex="-1" href="">Log out</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div><!--/.navbar-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
{% block sidebar %}
|
||||
<div class="col-md-3">
|
||||
<div class="list-group">
|
||||
<a href="{{url_for('shots.index')}}" class="list-group-item {% if title == 'shots' %}active{% endif %}">Shots</a>
|
||||
<a href="#" class="list-group-item {% if title == 'stats' %}active{% endif %}">Assets</a>
|
||||
</div>
|
||||
</div><!--/end col-md-3 -->
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
{% endblock %}
|
||||
</div><!--/row-->
|
||||
<hr>
|
||||
|
||||
<footer>
|
||||
<p>Attract 3 - Python powered</p>
|
||||
</footer>
|
||||
|
||||
</div><!--/.fluid-container-->
|
||||
|
||||
{% assets filters="jsmin",
|
||||
output="assets/packed/attract.js",
|
||||
"assets/js/jquery.min.js",
|
||||
"assets/js/bootstrap.min.js",
|
||||
"assets/js/jquery.dataTables.min.js",
|
||||
"assets/js/jquery.dataTables.fnGetColumnData.js",
|
||||
"assets/js/jquery.dataTables.fnFilterClear.js",
|
||||
"assets/js/jquery.dataTables.bootstrap.js",
|
||||
"assets/js/jquery.chosen.min.js",
|
||||
"assets/js/bootstrap-markdown.js",
|
||||
"assets/js/markdown.js",
|
||||
"assets/js/jquery.attract.js" %}
|
||||
<script type="text/javascript" src="{{ ASSET_URL }}"></script>
|
||||
{% endassets %}
|
||||
{% block footer_scripts %}
|
||||
{% endblock %}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,96 +0,0 @@
|
||||
{% extends 'layout.html' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="col-md-9">
|
||||
<h2>Add Node type</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<form method="POST" action="{{url_for('node_types.add')}}">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-group">
|
||||
{{ form.name.label }}
|
||||
{{ form.name(size=20, class='form-control') }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.description.label }}
|
||||
{{ form.description(size=20, class='form-control') }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.url.label }}
|
||||
{{ form.url(size=20, class='form-control') }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.is_extended.label }}
|
||||
{{ form.is_extended(class='form-control') }}
|
||||
</div>
|
||||
|
||||
<div data-toggle="fieldset" id="custom_field-fieldset">
|
||||
{{ form.custom_fields.label }} <button type="button" id="add_another_button">+</button>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Url</th>
|
||||
<th>Description</th>
|
||||
<th>Is required</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{% for custom_field in form.custom_fields %}
|
||||
<tr data-toggle="fieldset-entry">
|
||||
|
||||
{% for field in custom_field %}
|
||||
{% if field.type == 'HiddenField' %}
|
||||
{{field}}
|
||||
{% else %}
|
||||
<td>{{field}}</td>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<td><button type="button" data-toggle="fieldset-remove-row" id="custom_fields-{{loop.index0}}-remove">-</button></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<input class="btn btn-default" type="submit" value="Add Node Type">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block footer_scripts %}
|
||||
<script type="text/javascript">
|
||||
|
||||
$(function() {
|
||||
$("div[data-toggle=fieldset]").each(function() {
|
||||
var $this = $(this);
|
||||
|
||||
//Add new entry
|
||||
$this.find("button[data-toggle=fieldset-add-row]").click(function() {
|
||||
var target = $($(this).data("target"))
|
||||
console.log(target);
|
||||
var oldrow = target.find("tr[data-toggle=fieldset-entry]:last");
|
||||
var row = oldrow.clone(true, true);
|
||||
console.log(row.find(":input")[0]);
|
||||
var elem_id = row.find(":input")[0].id;
|
||||
var elem_num = parseInt(elem_id.replace(/.*-(\d{1,4})-.*/m, '$1')) + 1;
|
||||
row.attr('data-id', elem_num);
|
||||
row.find(":input").each(function() {
|
||||
console.log(this);
|
||||
var id = $(this).attr('id').replace('-' + (elem_num - 1) + '-', '-' + (elem_num) + '-');
|
||||
$(this).attr('name', id).attr('id', id).val('').removeAttr("checked");
|
||||
});
|
||||
oldrow.after(row);
|
||||
}); //End add new entry
|
||||
|
||||
//Remove row
|
||||
$this.find("button[data-toggle=fieldset-remove-row]").click(function() {
|
||||
if($this.find("tr[data-toggle=fieldset-entry]").length > 1) {
|
||||
var thisRow = $(this).closest("tr[data-toggle=fieldset-entry]");
|
||||
thisRow.remove();
|
||||
}
|
||||
}); //End remove row
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
@ -1,100 +0,0 @@
|
||||
{% extends 'layout.html' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="col-md-9">
|
||||
<h2>Edit Node type</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<form method="POST" action="{{url_for('node_types.edit', node_type_id=node_type.id)}}">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-group">
|
||||
{{ form.name.label }}
|
||||
{{ form.name(size=20, class='form-control') }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.description.label }}
|
||||
{{ form.description(size=20, class='form-control') }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.url.label }}
|
||||
{{ form.url(size=20, class='form-control') }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.is_extended.label }}
|
||||
{{ form.is_extended(class='form-control') }}
|
||||
</div>
|
||||
|
||||
<div data-toggle="fieldset" id="custom_fields-fieldset">
|
||||
{{ form.custom_fields.label }} <button type="button" data-toggle="fieldset-add-row" data-target="#custom_fields-fieldset">+</button>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Name</th>
|
||||
<th>Url</th>
|
||||
<th>Description</th>
|
||||
<th>Is required</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
{% for custom_field in form.custom_fields %}
|
||||
<tr data-toggle="fieldset-entry">
|
||||
|
||||
{% for field in custom_field %}
|
||||
{% if field.type == 'HiddenField' %}
|
||||
{{field}}
|
||||
{% else %}
|
||||
<td>{{field}}</td>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<td><button type="button" data-toggle="fieldset-remove-row" id="custom_fields-{{loop.index0}}-remove">-</button></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<input class="btn btn-default" type="submit" value="Edit Node Type">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block footer_scripts %}
|
||||
<script type="text/javascript">
|
||||
|
||||
$(function() {
|
||||
$("div[data-toggle=fieldset]").each(function() {
|
||||
var $this = $(this);
|
||||
|
||||
//Add new entry
|
||||
$this.find("button[data-toggle=fieldset-add-row]").click(function() {
|
||||
var target = $($(this).data("target"))
|
||||
console.log(target);
|
||||
var oldrow = target.find("tr[data-toggle=fieldset-entry]:last");
|
||||
var row = oldrow.clone(true, true);
|
||||
console.log(row.find(":input")[0]);
|
||||
var elem_id = row.find(":input")[0].id;
|
||||
var elem_num = parseInt(elem_id.replace(/.*-(\d{1,4})-.*/m, '$1')) + 1;
|
||||
row.attr('data-id', elem_num);
|
||||
row.find(":input").each(function() {
|
||||
console.log(this);
|
||||
var id = $(this).attr('id').replace('-' + (elem_num - 1) + '-', '-' + (elem_num) + '-');
|
||||
$(this).attr('name', id).attr('id', id).val('').removeAttr("checked");
|
||||
});
|
||||
oldrow.after(row);
|
||||
}); //End add new entry
|
||||
|
||||
//Remove row
|
||||
$this.find("button[data-toggle=fieldset-remove-row]").click(function() {
|
||||
if($this.find("tr[data-toggle=fieldset-entry]").length > 1) {
|
||||
var thisRow = $(this).closest("tr[data-toggle=fieldset-entry]");
|
||||
thisRow.remove();
|
||||
}
|
||||
}); //End remove row
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
@ -1,51 +0,0 @@
|
||||
{% extends 'layout.html' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="col-md-9">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<table cellpadding="0" cellspacing="0" border="0" class="table table-striped" id="shots">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Node Name</th>
|
||||
<th>Url</th>
|
||||
<th>Description</th>
|
||||
<th width="8%"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for node_type in node_types %}
|
||||
<tr id="row_{{node_type.id}}">
|
||||
<td>{{node_type.name}}</td>
|
||||
<td>{{node_type.url}}</td>
|
||||
<td>
|
||||
{% if node_type.description %}
|
||||
{{node_type.description|truncate(25)}}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a class="btn btn-default btn-xs" href="{{url_for('node_types.edit', node_type_id=node_type.id)}}"><i class="glyphicon glyphicon-edit"></i> Edit</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>Node Name</th>
|
||||
<th>Url</th>
|
||||
<th>Description</th>
|
||||
<th width="8%"></th>
|
||||
</tr>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<a href="{{url_for('node_types.add')}}" class="btn btn-default">Add</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -1,28 +0,0 @@
|
||||
{% extends 'layout.html' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="col-md-9">
|
||||
<h2>Add {{ node_type }}</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<form method="POST" action="{{url_for('nodes.add', node_type=node_type)}}">
|
||||
{% for field in form %}
|
||||
{% if field.name == 'csrf_token' %}
|
||||
{{ field }}
|
||||
{% else %}
|
||||
{% if field.type == "HiddenField" %}
|
||||
{{ field }}
|
||||
{% else %}
|
||||
<div class="form-group">
|
||||
{{ field.label }}
|
||||
{{ field(class='form-control') }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<input class="btn btn-default" type="submit" value="Create {{ node_type.name }}">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -1,32 +0,0 @@
|
||||
{% extends 'layout.html' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="col-md-9">
|
||||
<h2>Edit {{ node.node_type.name }}</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<form method="POST" action="{{url_for('nodes.edit', node_id=node.id)}}">
|
||||
{% for field in form %}
|
||||
{% if field.name == 'csrf_token' %}
|
||||
{{ field }}
|
||||
{% else %}
|
||||
{% if field.type == "HiddenField" %}
|
||||
{{ field }}
|
||||
{% else %}
|
||||
<div class="form-group">
|
||||
{{ field.label }}
|
||||
{{ field(class='form-control') }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<input class="btn btn-default" type="submit" value="Edit {{ node.node_type.name }}">
|
||||
<div class="pull-right">
|
||||
<a class="btn btn-default" href="#">Cancel</a>
|
||||
<a class="btn btn-danger" href="{{url_for('nodes.delete', node_id=node.id)}}">Delete</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -1,47 +0,0 @@
|
||||
{% extends 'layout.html' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="col-md-9">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<table cellpadding="0" cellspacing="0" border="0" class="table table-striped" id="nodes">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th width="8%"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for node in nodes %}
|
||||
<tr id="row_{{node.id}}">
|
||||
<td><a href="#">{{node.name}}</a></td>
|
||||
<td>
|
||||
{% if node.description %}
|
||||
{{node.description|truncate(25)}}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a class="btn btn-default btn-xs" href="{{url_for('nodes.edit', node_id=node.id)}}"><i class="glyphicon glyphicon-edit"></i> Edit</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<a href="#" class="btn btn-default">Add</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -1,35 +0,0 @@
|
||||
{% extends 'layout.html' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="col-md-9">
|
||||
<h2>Add shot</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<form method="POST" action="{{url_for('shots.add')}}">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-group">
|
||||
{{ form.name.label }}
|
||||
{{ form.name(size=20, class='form-control') }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.description.label }}
|
||||
{{ form.description(size=20, class='form-control') }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.duration.label }}
|
||||
{{ form.duration(size=20, class='form-control') }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.status_id.label }}
|
||||
{{ form.status_id(class='form-control') }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.notes.label }}
|
||||
{{ form.notes(class='form-control') }}
|
||||
</div>
|
||||
<input class="btn btn-default" type="submit" value="Create Shot">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -1,39 +0,0 @@
|
||||
{% extends 'layout.html' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="col-md-9">
|
||||
<h2>Edit shot</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<form method="POST" action="{{url_for('shots.edit', shot_id=shot_id)}}">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-group">
|
||||
{{ form.name.label }}
|
||||
{{ form.name(size=20, class='form-control') }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.description.label }}
|
||||
{{ form.description(size=20, class='form-control') }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.duration.label }}
|
||||
{{ form.duration(size=20, class='form-control') }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.status_id.label }}
|
||||
{{ form.status_id(class='form-control') }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{ form.notes.label }}
|
||||
{{ form.notes(class='form-control') }}
|
||||
</div>
|
||||
<input class="btn btn-default" type="submit" value="Edit Shot">
|
||||
<div class="pull-right">
|
||||
<a class="btn btn-default" href="{{url_for('shots.index')}}">Cancel</a>
|
||||
<a class="btn btn-danger" href="{{url_for('shots.delete', shot_id=shot_id)}}">Delete</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -1,63 +0,0 @@
|
||||
{% extends 'layout.html' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="col-md-9">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<table cellpadding="0" cellspacing="0" border="0" class="table table-striped" id="shots">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Shot Name</th>
|
||||
<th>Description</th>
|
||||
<th>Duration</th>
|
||||
<th>Status</th>
|
||||
<th>Tasks</th>
|
||||
<th>Notes</th>
|
||||
<th width="8%"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for shot in shots %}
|
||||
<tr id="row_{{shot['id']}}">
|
||||
<td><a href="{{url_for('shots.view', shot_id=shot['id'])}}">{{shot['name']}}</a></td>
|
||||
<td>
|
||||
{% if shot['description'] %}
|
||||
{{shot['description']|truncate(25)}}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{shot['duration']}}</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>
|
||||
{% if shot['notes'] %}
|
||||
{{shot['notes']|truncate(25)}}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a class="btn btn-default btn-xs" href="{{url_for('nodes.edit', node_id=shot['id'])}}"><i class="glyphicon glyphicon-edit"></i> Edit</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>Shot Name</th>
|
||||
<th>Description</th>
|
||||
<th>Duration</th>
|
||||
<th>Status</th>
|
||||
<th>Tasks</th>
|
||||
<th>Notes</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<a href="{{url_for('nodes.add', node_type='shot')}}" class="btn btn-default">Add</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -1,23 +0,0 @@
|
||||
{% extends 'layout.html' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="col-md-9">
|
||||
<h2>{{shot['name']}}</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<p>Picture goes here</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p>{{shot['description']}}</p>
|
||||
<p>
|
||||
{% if notes %}
|
||||
{{notes.value}}
|
||||
{% else %}
|
||||
No notes at the moment
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
@ -8,7 +8,7 @@ RESOURCE_METHODS = ['GET', 'POST', 'DELETE']
|
||||
ITEM_METHODS = ['GET', 'PATCH', 'PUT', 'DELETE']
|
||||
|
||||
|
||||
schema = {
|
||||
users_schema = {
|
||||
# Schema definition, based on Cerberus grammar. Check the Cerberus project
|
||||
# (https://github.com/nicolaiarocci/cerberus) for details.
|
||||
'firstname': {
|
||||
@ -26,9 +26,11 @@ schema = {
|
||||
'unique': True,
|
||||
},
|
||||
# 'role' is a list, and can only contain values from 'allowed'.
|
||||
# changed to string
|
||||
'role': {
|
||||
'type': 'list',
|
||||
'type': 'string',
|
||||
'allowed': ["author", "contributor", "copy"],
|
||||
'required': True,
|
||||
},
|
||||
# An embedded 'strongly-typed' dictionary.
|
||||
'location': {
|
||||
@ -36,7 +38,7 @@ schema = {
|
||||
'schema': {
|
||||
'address': {'type': 'string'},
|
||||
'city': {'type': 'string'}
|
||||
},
|
||||
}
|
||||
},
|
||||
'born': {
|
||||
'type': 'datetime',
|
||||
@ -48,21 +50,52 @@ nodes_schema = {
|
||||
'type': 'string',
|
||||
'minlength': 1,
|
||||
'maxlength': 128,
|
||||
'required': True,
|
||||
},
|
||||
'description': {
|
||||
'type': 'string',
|
||||
'minlength': 1,
|
||||
'maxlength': 128,
|
||||
},
|
||||
'thumbnail': {
|
||||
'type': 'string',
|
||||
'minlength': 1,
|
||||
'maxlength': 128,
|
||||
},
|
||||
'parent': {
|
||||
'type': 'objectid',
|
||||
# 'data_relation': {
|
||||
# 'resource': 'node',
|
||||
# 'field': '_id',
|
||||
# },
|
||||
'data_relation': {
|
||||
'resource': 'nodes',
|
||||
'field': '_id',
|
||||
},
|
||||
},
|
||||
'node_type' : {
|
||||
'type' : 'string',
|
||||
'validcf' : True,
|
||||
'required': True,
|
||||
'data_relation': {
|
||||
'resource': 'node_types',
|
||||
'field': '_id',
|
||||
},
|
||||
},
|
||||
# 'custom_fields' : {
|
||||
# 'type' : 'dict'
|
||||
# }
|
||||
'properties' : {
|
||||
'type' : 'dict',
|
||||
'valid_properties' : True,
|
||||
'required': True,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
node_types_schema = {
|
||||
'name': {
|
||||
'type': 'string',
|
||||
'minlength': 1,
|
||||
'maxlength': 128,
|
||||
'required': True,
|
||||
},
|
||||
'dyn_schema': {
|
||||
'type': 'dict',
|
||||
'required': True,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -74,15 +107,22 @@ nodes = {
|
||||
# most global settings can be overridden at resource level
|
||||
'resource_methods': ['GET', 'POST'],
|
||||
|
||||
'allowed_roles': ['author', 'contributor'],
|
||||
|
||||
'schema': nodes_schema
|
||||
}
|
||||
|
||||
|
||||
node_types = {
|
||||
|
||||
people = {
|
||||
# 'title' tag used in item links. Defaults to the resource title minus
|
||||
# the final, plural 's' (works fine in most cases but not for 'people')
|
||||
'item_title': 'person',
|
||||
'resource_methods': ['GET', 'POST'],
|
||||
|
||||
'schema' : node_types_schema,
|
||||
}
|
||||
|
||||
|
||||
users = {
|
||||
'item_title': 'user',
|
||||
|
||||
# by default the standard item entry point is defined as
|
||||
# '/people/<ObjectId>'. We leave it untouched, and we also enable an
|
||||
@ -100,12 +140,19 @@ people = {
|
||||
# most global settings can be overridden at resource level
|
||||
'resource_methods': ['GET', 'POST'],
|
||||
|
||||
'schema': schema
|
||||
# Allow 'token' to be returned with POST responses
|
||||
'extra_response_fields': ['token'],
|
||||
|
||||
'public_methods': ['GET', 'POST'],
|
||||
# 'public_item_methods': ['GET'],
|
||||
|
||||
'schema': users_schema
|
||||
}
|
||||
|
||||
|
||||
DOMAIN = {
|
||||
'people': people,
|
||||
'nodes' : nodes
|
||||
'users': users,
|
||||
'nodes' : nodes,
|
||||
'node_types': node_types,
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user