Browse Source

YOLO FIRST COMMIT

master
Dashie der otter 4 years ago
commit
77e8c3548c
100 changed files with 18265 additions and 0 deletions
  1. 10
    0
      .gitignore
  2. 3
    0
      .gitmodules
  3. 26
    0
      config.py.sample
  4. 35
    0
      dbseed.py
  5. 18
    0
      forms.py
  6. 1
    0
      migrations/README
  7. 45
    0
      migrations/alembic.ini
  8. 87
    0
      migrations/env.py
  9. 22
    0
      migrations/script.py.mako
  10. 32
    0
      migrations/versions/2bd9ce04df01_.py
  11. 39
    0
      migrations/versions/501d2a40e251_.py
  12. 42
    0
      migrations/versions/518cfab913f1_.py
  13. 189
    0
      migrations/versions/89a36a4580f_.py
  14. 270
    0
      models.py
  15. 26
    0
      static/bower_components/bootstrap-social/.bower.json
  16. 11
    0
      static/bower_components/bootstrap-social/.editorconfig
  17. 2
    0
      static/bower_components/bootstrap-social/.gitignore
  18. 58
    0
      static/bower_components/bootstrap-social/README.md
  19. 101
    0
      static/bower_components/bootstrap-social/bootstrap-social.css
  20. 114
    0
      static/bower_components/bootstrap-social/bootstrap-social.less
  21. 114
    0
      static/bower_components/bootstrap-social/bootstrap-social.scss
  22. 14
    0
      static/bower_components/bootstrap-social/bower.json
  23. 47
    0
      static/bower_components/bootstrap/.bower.json
  24. 509
    0
      static/bower_components/bootstrap/Gruntfile.js
  25. 21
    0
      static/bower_components/bootstrap/LICENSE
  26. 132
    0
      static/bower_components/bootstrap/README.md
  27. 38
    0
      static/bower_components/bootstrap/bower.json
  28. 476
    0
      static/bower_components/bootstrap/dist/css/bootstrap-theme.css
  29. 1
    0
      static/bower_components/bootstrap/dist/css/bootstrap-theme.css.map
  30. 5
    0
      static/bower_components/bootstrap/dist/css/bootstrap-theme.min.css
  31. 6566
    0
      static/bower_components/bootstrap/dist/css/bootstrap.css
  32. 1
    0
      static/bower_components/bootstrap/dist/css/bootstrap.css.map
  33. 5
    0
      static/bower_components/bootstrap/dist/css/bootstrap.min.css
  34. BIN
      static/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot
  35. 288
    0
      static/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg
  36. BIN
      static/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf
  37. BIN
      static/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff
  38. BIN
      static/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2
  39. 2306
    0
      static/bower_components/bootstrap/dist/js/bootstrap.js
  40. 7
    0
      static/bower_components/bootstrap/dist/js/bootstrap.min.js
  41. 13
    0
      static/bower_components/bootstrap/dist/js/npm.js
  42. BIN
      static/bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot
  43. 288
    0
      static/bower_components/bootstrap/fonts/glyphicons-halflings-regular.svg
  44. BIN
      static/bower_components/bootstrap/fonts/glyphicons-halflings-regular.ttf
  45. BIN
      static/bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff
  46. BIN
      static/bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff2
  47. 7
    0
      static/bower_components/bootstrap/grunt/.jshintrc
  48. 23
    0
      static/bower_components/bootstrap/grunt/bs-commonjs-generator.js
  49. 41
    0
      static/bower_components/bootstrap/grunt/bs-glyphicons-data-generator.js
  50. 238
    0
      static/bower_components/bootstrap/grunt/bs-lessdoc-parser.js
  51. 46
    0
      static/bower_components/bootstrap/grunt/bs-raw-files-generator.js
  52. 45
    0
      static/bower_components/bootstrap/grunt/configBridge.json
  53. 82
    0
      static/bower_components/bootstrap/grunt/sauce_browsers.yml
  54. 36
    0
      static/bower_components/bootstrap/js/.jscsrc
  55. 15
    0
      static/bower_components/bootstrap/js/.jshintrc
  56. 162
    0
      static/bower_components/bootstrap/js/affix.js
  57. 94
    0
      static/bower_components/bootstrap/js/alert.js
  58. 116
    0
      static/bower_components/bootstrap/js/button.js
  59. 237
    0
      static/bower_components/bootstrap/js/carousel.js
  60. 211
    0
      static/bower_components/bootstrap/js/collapse.js
  61. 161
    0
      static/bower_components/bootstrap/js/dropdown.js
  62. 324
    0
      static/bower_components/bootstrap/js/modal.js
  63. 113
    0
      static/bower_components/bootstrap/js/popover.js
  64. 175
    0
      static/bower_components/bootstrap/js/scrollspy.js
  65. 153
    0
      static/bower_components/bootstrap/js/tab.js
  66. 472
    0
      static/bower_components/bootstrap/js/tooltip.js
  67. 59
    0
      static/bower_components/bootstrap/js/transition.js
  68. 304
    0
      static/bower_components/bootstrap/less/.csscomb.json
  69. 19
    0
      static/bower_components/bootstrap/less/.csslintrc
  70. 73
    0
      static/bower_components/bootstrap/less/alerts.less
  71. 65
    0
      static/bower_components/bootstrap/less/badges.less
  72. 50
    0
      static/bower_components/bootstrap/less/bootstrap.less
  73. 26
    0
      static/bower_components/bootstrap/less/breadcrumbs.less
  74. 243
    0
      static/bower_components/bootstrap/less/button-groups.less
  75. 160
    0
      static/bower_components/bootstrap/less/buttons.less
  76. 269
    0
      static/bower_components/bootstrap/less/carousel.less
  77. 34
    0
      static/bower_components/bootstrap/less/close.less
  78. 69
    0
      static/bower_components/bootstrap/less/code.less
  79. 34
    0
      static/bower_components/bootstrap/less/component-animations.less
  80. 214
    0
      static/bower_components/bootstrap/less/dropdowns.less
  81. 566
    0
      static/bower_components/bootstrap/less/forms.less
  82. 301
    0
      static/bower_components/bootstrap/less/glyphicons.less
  83. 84
    0
      static/bower_components/bootstrap/less/grid.less
  84. 166
    0
      static/bower_components/bootstrap/less/input-groups.less
  85. 50
    0
      static/bower_components/bootstrap/less/jumbotron.less
  86. 64
    0
      static/bower_components/bootstrap/less/labels.less
  87. 124
    0
      static/bower_components/bootstrap/less/list-group.less
  88. 61
    0
      static/bower_components/bootstrap/less/media.less
  89. 39
    0
      static/bower_components/bootstrap/less/mixins.less
  90. 14
    0
      static/bower_components/bootstrap/less/mixins/alerts.less
  91. 8
    0
      static/bower_components/bootstrap/less/mixins/background-variant.less
  92. 18
    0
      static/bower_components/bootstrap/less/mixins/border-radius.less
  93. 52
    0
      static/bower_components/bootstrap/less/mixins/buttons.less
  94. 7
    0
      static/bower_components/bootstrap/less/mixins/center-block.less
  95. 22
    0
      static/bower_components/bootstrap/less/mixins/clearfix.less
  96. 85
    0
      static/bower_components/bootstrap/less/mixins/forms.less
  97. 59
    0
      static/bower_components/bootstrap/less/mixins/gradients.less
  98. 91
    0
      static/bower_components/bootstrap/less/mixins/grid-framework.less
  99. 122
    0
      static/bower_components/bootstrap/less/mixins/grid.less
  100. 0
    0
      static/bower_components/bootstrap/less/mixins/hide-text.less

+ 10
- 0
.gitignore View File

@@ -0,0 +1,10 @@
__pycache__
.idea
instance/uploads/*
*.db
export.csv
*.swp
*.pyc
.ropeproject
config.py
StockazNG.komodoproject

+ 3
- 0
.gitmodules View File

@@ -0,0 +1,3 @@
[submodule "texttable"]
path = texttable
url = https://github.com/bufordtaylor/python-texttable.git

+ 26
- 0
config.py.sample View File

@@ -0,0 +1,26 @@
DEBUG = False

SECRET_KEY = 'loleloe32j2j423kh43k2jh43k2j4h2k'
SQLALCHEMY_DATABASE_URI = 'postgresql+psycopg2://user@localhost/stockazng'
SQLALCHEMY_DATABASE_URI = 'postgresql+pg8000://user@localhost/stockazng'

SECURITY_CONFIRMABLE = False
SECURITY_REGISTERABLE = True # deactivate registration
SECURITY_RECOVERABLE = True
SECURITY_TRACKABLE = False
SECURITY_CHANGEABLE = True
UPLOADED_FILES_DEST = 'uploads/'
SECURITY_PASSWORD_HASH = 'bcrypt'
SECURITY_PASSWORD_SALT = 'pepperponiesandbirds'

SECURITY_SEND_REGISTER_EMAIL = False
SECURITY_SEND_PASSWORD_CHANGE_EMAIL = False
SECURITY_SEND_PASSWORD_RESET_NOTICE_EMAIL = False

BOOTSTRAP_USE_MINIFIED = True
BOOTSTRAP_SERVE_LOCAL = True
BOOTSTRAP_CDN_FORCE_SSL = True
BOOTSTRAP_QUERYSTRING_REVVING = True

DEBUG_TB_PROFILER_ENABLED = True
DEBUG_TB_INTERCEPT_REDIRECTS = False

+ 35
- 0
dbseed.py View File

@@ -0,0 +1,35 @@
from models import user_datastore, PartCategory, FootprintCategory


def make_db_seed(db):
print("== Seeding database")
seed_users(db)
seed_root_categories(db)


def seed_users(db):
print("++ Seeding users")
user_datastore.create_user(
email='dashie@sigpipe.me',
password='fluttershy',
name='toto'
)
db.session.commit()
return


def seed_root_categories(db):
print("++ Seeding root categories")
a = PartCategory(parent_id=None)
a.name = "Root"
a.description = "Root category"


b = FootprintCategory()
b.name = "Root"
b.description = "Root category"
b.parent = None

db.session.add(a)
db.session.add(b)
db.session.commit()

+ 18
- 0
forms.py View File

@@ -0,0 +1,18 @@
from flask.ext.wtf import Form
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
from flask_security import RegisterForm
from models import db
from wtforms_alchemy import model_form_factory

BaseModelForm = model_form_factory(Form)


class ModelForm(BaseModelForm):
@classmethod
def get_session(self):
return db.session


class ExtendedRegisterForm(RegisterForm):
name = StringField('Name', [DataRequired()])

+ 1
- 0
migrations/README View File

@@ -0,0 +1 @@
Generic single-database configuration.

+ 45
- 0
migrations/alembic.ini View File

@@ -0,0 +1,45 @@
# A generic, single database configuration.

[alembic]
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s

# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false


# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console
qualname =

[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S

+ 87
- 0
migrations/env.py View File

@@ -0,0 +1,87 @@
from __future__ import with_statement
from alembic import context
from sqlalchemy import engine_from_config, pool
from logging.config import fileConfig
import logging

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config

# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
logger = logging.getLogger('alembic.env')

# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
from flask import current_app
config.set_main_option('sqlalchemy.url',
current_app.config.get('SQLALCHEMY_DATABASE_URI'))
target_metadata = current_app.extensions['migrate'].db.metadata

# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.


def run_migrations_offline():
"""Run migrations in 'offline' mode.

This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.

Calls to context.execute() here emit the given string to the
script output.

"""
url = config.get_main_option("sqlalchemy.url")
context.configure(url=url)

with context.begin_transaction():
context.run_migrations()


def run_migrations_online():
"""Run migrations in 'online' mode.

In this scenario we need to create an Engine
and associate a connection with the context.

"""

# this callback is used to prevent an auto-migration from being generated
# when there are no changes to the schema
# reference: http://alembic.readthedocs.org/en/latest/cookbook.html
def process_revision_directives(context, revision, directives):
if getattr(config.cmd_opts, 'autogenerate', False):
script = directives[0]
if script.upgrade_ops.is_empty():
directives[:] = []
logger.info('No changes in schema detected.')

engine = engine_from_config(config.get_section(config.config_ini_section),
prefix='sqlalchemy.',
poolclass=pool.NullPool)

connection = engine.connect()
context.configure(connection=connection,
target_metadata=target_metadata,
process_revision_directives=process_revision_directives,
**current_app.extensions['migrate'].configure_args)

try:
with context.begin_transaction():
context.run_migrations()
finally:
connection.close()

if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()

+ 22
- 0
migrations/script.py.mako View File

@@ -0,0 +1,22 @@
"""${message}

Revision ID: ${up_revision}
Revises: ${down_revision}
Create Date: ${create_date}

"""

# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}

from alembic import op
import sqlalchemy as sa
${imports if imports else ""}

def upgrade():
${upgrades if upgrades else "pass"}


def downgrade():
${downgrades if downgrades else "pass"}

+ 32
- 0
migrations/versions/2bd9ce04df01_.py View File

@@ -0,0 +1,32 @@
"""Fix parameter relation

Revision ID: 2bd9ce04df01
Revises: 89a36a4580f
Create Date: 2015-09-23 11:38:10.793639

"""

# revision identifiers, used by Alembic.
revision = '2bd9ce04df01'
down_revision = '89a36a4580f'

from alembic import op
import sqlalchemy as sa


def upgrade():
### commands auto generated by Alembic - please adjust! ###
op.add_column('part_parameter', sa.Column('part_id', sa.Integer(), nullable=False))
op.create_foreign_key(None, 'part_parameter', 'part', ['part_id'], ['id'])
op.drop_constraint(u'rel_distributors_distributor_id_fkey', 'rel_distributors', type_='foreignkey')
op.create_foreign_key(None, 'rel_distributors', 'distributor', ['distributor_id'], ['id'])
### end Alembic commands ###


def downgrade():
### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'rel_distributors', type_='foreignkey')
op.create_foreign_key(u'rel_distributors_distributor_id_fkey', 'rel_distributors', 'manufacturer', ['distributor_id'], ['id'])
op.drop_constraint(None, 'part_parameter', type_='foreignkey')
op.drop_column('part_parameter', 'part_id')
### end Alembic commands ###

+ 39
- 0
migrations/versions/501d2a40e251_.py View File

@@ -0,0 +1,39 @@
"""Add project

Revision ID: 501d2a40e251
Revises: 2bd9ce04df01
Create Date: 2015-09-23 14:13:57.546872

"""

# revision identifiers, used by Alembic.
revision = '501d2a40e251'
down_revision = '2bd9ce04df01'

from alembic import op
import sqlalchemy as sa


def upgrade():
### commands auto generated by Alembic - please adjust! ###
op.create_table('project',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=255), nullable=False),
sa.Column('description', sa.String(length=255), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.create_table('rel_projects',
sa.Column('part_id', sa.Integer(), nullable=False),
sa.Column('project_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['part_id'], ['part.id'], ),
sa.ForeignKeyConstraint(['project_id'], ['project.id'], )
)
### end Alembic commands ###


def downgrade():
### commands auto generated by Alembic - please adjust! ###
op.drop_table('rel_projects')
op.drop_table('project')
### end Alembic commands ###

+ 42
- 0
migrations/versions/518cfab913f1_.py View File

@@ -0,0 +1,42 @@
"""empty message

Revision ID: 518cfab913f1
Revises: 501d2a40e251
Create Date: 2015-09-23 15:39:16.674276

"""

# revision identifiers, used by Alembic.
revision = '518cfab913f1'
down_revision = '501d2a40e251'

from alembic import op
import sqlalchemy as sa


def upgrade():
### commands auto generated by Alembic - please adjust! ###
op.add_column('part_category', sa.Column('level', sa.Integer(), nullable=False))
op.add_column('part_category', sa.Column('lft', sa.Integer(), nullable=False))
op.add_column('part_category', sa.Column('parent_id', sa.Integer(), nullable=True))
op.add_column('part_category', sa.Column('rgt', sa.Integer(), nullable=False))
op.add_column('part_category', sa.Column('tree_id', sa.Integer(), nullable=True))
op.create_index('part_category_level_idx', 'part_category', ['level'], unique=False)
op.create_index('part_category_lft_idx', 'part_category', ['lft'], unique=False)
op.create_index('part_category_rgt_idx', 'part_category', ['rgt'], unique=False)
op.create_foreign_key(None, 'part_category', 'part_category', ['parent_id'], ['id'], ondelete='CASCADE')
### end Alembic commands ###


def downgrade():
### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'part_category', type_='foreignkey')
op.drop_index('part_category_rgt_idx', table_name='part_category')
op.drop_index('part_category_lft_idx', table_name='part_category')
op.drop_index('part_category_level_idx', table_name='part_category')
op.drop_column('part_category', 'tree_id')
op.drop_column('part_category', 'rgt')
op.drop_column('part_category', 'parent_id')
op.drop_column('part_category', 'lft')
op.drop_column('part_category', 'level')
### end Alembic commands ###

+ 189
- 0
migrations/versions/89a36a4580f_.py View File

@@ -0,0 +1,189 @@
"""Initial schema bdd

Revision ID: 89a36a4580f
Revises: None
Create Date: 2015-09-23 11:23:18.919900

"""

# revision identifiers, used by Alembic.
revision = '89a36a4580f'
down_revision = None

from alembic import op
import sqlalchemy as sa


def upgrade():
### commands auto generated by Alembic - please adjust! ###
op.create_table('distributor',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=255), nullable=False),
sa.Column('address', sa.String(length=255), nullable=True),
sa.Column('url', sa.String(length=255), nullable=True),
sa.Column('email', sa.String(length=255), nullable=True),
sa.Column('comment', sa.String(length=255), nullable=True),
sa.Column('phone', sa.String(length=255), nullable=True),
sa.Column('fax', sa.String(length=255), nullable=True),
sa.Column('skuurl', sa.String(length=255), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.create_table('footprint_category',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=255), nullable=True),
sa.Column('description', sa.String(length=255), nullable=True),
sa.Column('parent', sa.Integer(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_table('manufacturer',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=255), nullable=False),
sa.Column('address', sa.String(length=255), nullable=True),
sa.Column('url', sa.String(length=255), nullable=True),
sa.Column('email', sa.String(length=255), nullable=True),
sa.Column('comment', sa.String(length=255), nullable=True),
sa.Column('phone', sa.String(length=255), nullable=True),
sa.Column('fax', sa.String(length=255), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.create_table('part_category',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=255), nullable=True),
sa.Column('description', sa.String(length=255), nullable=True),
sa.Column('parent', sa.Integer(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_table('role',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=80), nullable=False),
sa.Column('description', sa.String(length=255), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.create_table('storage_category',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=255), nullable=True),
sa.Column('description', sa.String(length=255), nullable=True),
sa.Column('parent', sa.Integer(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_table('unit',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=255), nullable=True),
sa.Column('description', sa.String(length=255), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_table('user',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('email', sa.String(length=255), nullable=False),
sa.Column('name', sa.String(length=255), nullable=False),
sa.Column('password', sa.String(length=255), nullable=False),
sa.Column('active', sa.Boolean(), nullable=True),
sa.Column('confirmed_at', sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('email'),
sa.UniqueConstraint('name')
)
op.create_table('apitoken',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('token', sa.String(), nullable=False),
sa.Column('secret', sa.String(), nullable=False),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('secret'),
sa.UniqueConstraint('token')
)
op.create_table('footprint',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=64), nullable=True),
sa.Column('description', sa.String(length=255), nullable=True),
sa.Column('footprint_category_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['footprint_category_id'], ['footprint_category.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.create_table('part_parameter',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=64), nullable=True),
sa.Column('description', sa.String(length=255), nullable=True),
sa.Column('unit_value', sa.String(length=255), nullable=True),
sa.Column('unit_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['unit_id'], ['unit.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.create_table('roles_users',
sa.Column('user_id', sa.Integer(), nullable=True),
sa.Column('role_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['role_id'], ['role.id'], ),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], )
)
op.create_table('storage',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=64), nullable=True),
sa.Column('description', sa.String(length=255), nullable=True),
sa.Column('storage_category_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['storage_category_id'], ['storage_category.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.create_table('part',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=255), nullable=True),
sa.Column('description', sa.String(length=255), nullable=True),
sa.Column('comment', sa.String(length=255), nullable=True),
sa.Column('stock_level', sa.Integer(), nullable=True),
sa.Column('min_stock_level', sa.Integer(), nullable=True),
sa.Column('needs_review', sa.Boolean(), nullable=True),
sa.Column('status', sa.String(length=255), nullable=True),
sa.Column('condition', sa.String(length=255), nullable=True),
sa.Column('partcategory_id', sa.Integer(), nullable=False),
sa.Column('footprint_id', sa.Integer(), nullable=False),
sa.Column('unit_id', sa.Integer(), nullable=False),
sa.Column('storage_id', sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['footprint_id'], ['footprint.id'], ),
sa.ForeignKeyConstraint(['partcategory_id'], ['part_category.id'], ),
sa.ForeignKeyConstraint(['storage_id'], ['storage.id'], ),
sa.ForeignKeyConstraint(['unit_id'], ['unit.id'], ),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.create_table('rel_distributors',
sa.Column('distributor_id', sa.Integer(), nullable=False),
sa.Column('part_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['distributor_id'], ['manufacturer.id'], ),
sa.ForeignKeyConstraint(['part_id'], ['part.id'], )
)
op.create_table('rel_manufacturer',
sa.Column('manufacturer_id', sa.Integer(), nullable=False),
sa.Column('part_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['manufacturer_id'], ['manufacturer.id'], ),
sa.ForeignKeyConstraint(['part_id'], ['part.id'], )
)
### end Alembic commands ###


def downgrade():
### commands auto generated by Alembic - please adjust! ###
op.drop_table('rel_manufacturer')
op.drop_table('rel_distributors')
op.drop_table('part')
op.drop_table('storage')
op.drop_table('roles_users')
op.drop_table('part_parameter')
op.drop_table('footprint')
op.drop_table('apitoken')
op.drop_table('user')
op.drop_table('unit')
op.drop_table('storage_category')
op.drop_table('role')
op.drop_table('part_category')
op.drop_table('manufacturer')
op.drop_table('footprint_category')
op.drop_table('distributor')
### end Alembic commands ###

+ 270
- 0
models.py View File

@@ -0,0 +1,270 @@
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.security import SQLAlchemyUserDatastore, \
UserMixin, RoleMixin
from sqlalchemy_mptt.mixins import BaseNestedSets

db = SQLAlchemy()

roles_users = db.Table('roles_users',
db.Column('user_id', db.Integer(),
db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(),
db.ForeignKey('role.id')))


class Role(db.Model, RoleMixin):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(
db.String(80),
unique=True,
nullable=False,
info={'label': 'Name'})
description = db.Column(
db.String(255),
info={'label': 'Description'})


class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(
db.String(255),
unique=True,
nullable=False,
info={'label': 'Email'}
)
name = db.Column(
db.String(255),
unique=True,
nullable=False,
info={'label': 'Name'}
)
password = db.Column(
db.String(255),
nullable=False,
info={'label': 'Password'}
)
active = db.Column(db.Boolean())
confirmed_at = db.Column(db.DateTime())
roles = db.relationship('Role', secondary=roles_users,
backref=db.backref('users', lazy='dynamic'))
parts = db.relationship('Part', backref='user', lazy='dynamic')
apitokens = db.relationship('Apitoken', backref='user', lazy='dynamic')


class Apitoken(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer(), db.ForeignKey('user.id'), nullable=False)
token = db.Column(db.String(),
unique=True,
nullable=False,
info={'label': 'Token'}
)
secret = db.Column(db.String(),
unique=True,
nullable=False,
info={'label': 'Secret'}
)


user_datastore = SQLAlchemyUserDatastore(db, User, Role)


class PartCategory(db.Model, BaseNestedSets):
__tablename__ = "part_category"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), unique=False, nullable=True)
description = db.Column(db.String(255), unique=False, nullable=True)
parent = db.Column(db.Integer, nullable=True, default=None)

def __repr__(self):
return "<Node (%s)>" % self.id


class Unit(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), unique=False, nullable=True)
description = db.Column(db.String(255), unique=False, nullable=True)


class Manufacturer(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(
db.String(255),
unique=True,
nullable=False,
info={'label': 'Name'}
)
address = db.Column(
db.String(255),
nullable=True,
info={'label': 'Address'}
)
url = db.Column(
db.String(255),
nullable=True,
info={'label': 'URL'}
)
email = db.Column(
db.String(255),
nullable=True,
info={'label': 'Email'}
)
comment = db.Column(
db.String(255),
nullable=True,
info={'label': 'Comment'}
)
phone = db.Column(
db.String(255),
nullable=True,
info={'label': 'Phone'}
)
fax = db.Column(
db.String(255),
nullable=True,
info={'label': 'FAX'}
)
# ICs Logos


class Distributor(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(
db.String(255),
unique=True,
nullable=False,
info={'label': 'Name'}
)
address = db.Column(
db.String(255),
nullable=True,
info={'label': 'Address'}
)
url = db.Column(
db.String(255),
nullable=True,
info={'label': 'URL'}
)
email = db.Column(
db.String(255),
nullable=True,
info={'label': 'Email'}
)
comment = db.Column(
db.String(255),
nullable=True,
info={'label': 'Comment'}
)
phone = db.Column(
db.String(255),
nullable=True,
info={'label': 'Phone'}
)
fax = db.Column(
db.String(255),
nullable=True,
info={'label': 'FAX'}
)
skuurl = db.Column(
db.String(255),
nullable=True,
info={'label': 'SKU Url'}
)


class Project(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(
db.String(255),
unique=True,
nullable=False,
info={'label': 'Name'}
)
description = db.Column(
db.String(255),
nullable=True,
info={'label': 'Description'}
)


class FootprintCategory(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), unique=False, nullable=True)
description = db.Column(db.String(255), unique=False, nullable=True)
parent = db.Column(db.Integer, nullable=True, default=None)
footprints = db.relationship('Footprint', backref='footprint_category', lazy='dynamic')


class Footprint(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
description = db.Column(db.String(255), nullable=True)
footprint_category_id = db.Column(db.Integer, db.ForeignKey('footprint_category.id'), nullable=True)
# footprint attachments (includes images?)


class StorageCategory(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), unique=False, nullable=True)
description = db.Column(db.String(255), unique=False, nullable=True)
parent = db.Column(db.Integer, nullable=True, default=None)
footprints = db.relationship('Storage', backref='storage_category', lazy='dynamic')


class Storage(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
description = db.Column(db.String(255), nullable=True)
storage_category_id = db.Column(db.Integer, db.ForeignKey('storage_category.id'), nullable=True)
# storage image


class PartParameter(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
description = db.Column(db.String(255), nullable=True)
unit_value = db.Column(db.String(255), nullable=True)
unit_id = db.Column(db.Integer(), db.ForeignKey('unit.id'), nullable=True)
part_id = db.Column(db.Integer(), db.ForeignKey('part.id'), nullable=False)

# links #
rel_manufacturers = db.Table('rel_manufacturer',
db.Column('part_id', db.Integer(), db.ForeignKey('part.id'), nullable=False),
db.Column('manufacturer_id', db.Integer(), db.ForeignKey('manufacturer.id'),
nullable=False)
)
rel_distributors = db.Table('rel_distributors',
db.Column('part_id', db.Integer(), db.ForeignKey('part.id'), nullable=False),
db.Column('distributor_id', db.Integer(), db.ForeignKey('distributor.id'), nullable=False)
)
rel_projects = db.Table('rel_projects',
db.Column('part_id', db.Integer(), db.ForeignKey('part.id'), nullable=False),
db.Column('project_id', db.Integer(), db.ForeignKey('project.id'), nullable=False)
)


class Part(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), unique=True)
description = db.Column(db.String(255), nullable=True)
comment = db.Column(db.String(255), nullable=True)
stock_level = db.Column(db.Integer(), default=0)
min_stock_level = db.Column(db.Integer(), default=0)
needs_review = db.Column(db.Boolean(), default=0)
status = db.Column(db.String(255))
condition = db.Column(db.String(255))

partcategory_id = db.Column(db.Integer(), db.ForeignKey('part_category.id'), nullable=False)
footprint_id = db.Column(db.Integer(), db.ForeignKey('footprint.id'), nullable=False)
unit_id = db.Column(db.Integer(), db.ForeignKey('unit.id'), nullable=False)
storage_id = db.Column(db.Integer(), db.ForeignKey('storage.id'), nullable=False)

manufacturers = db.relationship('Manufacturer', secondary=rel_manufacturers, backref='part')
distributors = db.relationship('Distributor', secondary=rel_distributors, backref='part')
projects = db.relationship('Project', secondary=rel_projects, backref='part')

parameters = db.relationship('PartParameter', backref='part', lazy='dynamic')

# images / attachments
user_id = db.Column(db.Integer(), db.ForeignKey('user.id'), nullable=False)


+ 26
- 0
static/bower_components/bootstrap-social/.bower.json View File

@@ -0,0 +1,26 @@
{
"name": "bootstrap-social",
"main": "bootstrap-social.css",
"licence": "MIT",
"ignore": [
"assets",
"index.html",
"LICENCE"
],
"dependencies": {
"bootstrap": "~3",
"font-awesome": "~4.2"
},
"homepage": "https://github.com/lipis/bootstrap-social",
"version": "4.8.0",
"_release": "4.8.0",
"_resolution": {
"type": "version",
"tag": "4.8.0",
"commit": "918fc55c3c938377a7618ec0f115846e50d4b883"
},
"_source": "git://github.com/lipis/bootstrap-social.git",
"_target": "~4.8.0",
"_originalSource": "bootstrap-social",
"_direct": true
}

+ 11
- 0
static/bower_components/bootstrap-social/.editorconfig View File

@@ -0,0 +1,11 @@
# editorconfig.org

root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

+ 2
- 0
static/bower_components/bootstrap-social/.gitignore View File

@@ -0,0 +1,2 @@
.DS_Store
dev

+ 58
- 0
static/bower_components/bootstrap-social/README.md View File

@@ -0,0 +1,58 @@
Social Buttons for Bootstrap
============================

Social Buttons made in pure CSS based on
[Bootstrap](http://twbs.github.io/bootstrap/) and
[Font Awesome](http://fortawesome.github.io/Font-Awesome/)!

[Check the live demo!](http://lipis.github.io/bootstrap-social)

Installation
------------

Include the `bootstrap-social.css` or `bootstrap-social.less` in your project, or
install it through [Bower](http://bower.io/):

bower install bootstrap-social

Available classes
-----------------
- `btn-adn`
- `btn-bitbucket`
- `btn-dropbox`
- `btn-facebook`
- `btn-flickr`
- `btn-foursquare`
- `btn-github`
- `btn-google-plus`
- `btn-instagram`
- `btn-linkedin`
- `btn-microsoft`
- `btn-openid`
- `btn-reddit`
- `btn-soundcloud`
- `btn-tumblr`
- `btn-twitter`
- `btn-vimeo`
- `btn-vk`
- `btn-yahoo`

Examples
--------

```html
<a class="btn btn-block btn-social btn-twitter">
<i class="fa fa-twitter"></i>
Sign in with Twitter
</a>

<a class="btn btn-social-icon btn-twitter">
<i class="fa fa-twitter"></i>
</a>
```

Pull Requests
-------------
If you are about to create a new **Pull Request** for adding a new button don't
update the minified `bootstrap-social.css` file. It will be generated
automatically after a successful merge.

+ 101
- 0
static/bower_components/bootstrap-social/bootstrap-social.css
File diff suppressed because it is too large
View File


+ 114
- 0
static/bower_components/bootstrap-social/bootstrap-social.less View File

@@ -0,0 +1,114 @@
/*
* Social Buttons for Bootstrap
*
* Copyright 2013-2014 Panayiotis Lipiridis
* Licensed under the MIT License
*
* https://github.com/lipis/bootstrap-social
*/

@bs-height-base: (@line-height-computed + @padding-base-vertical * 2);
@bs-height-lg: (floor(@font-size-large * @line-height-base) + @padding-large-vertical * 2);
@bs-height-sm: (floor(@font-size-small * 1.5) + @padding-small-vertical * 2);
@bs-height-xs: (floor(@font-size-small * 1.2) + @padding-small-vertical + 1);

.btn-social {
position: relative;
padding-left: (@bs-height-base + @padding-base-horizontal);
text-align: left;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
> :first-child {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: @bs-height-base;
line-height: (@bs-height-base + 2);
font-size: 1.6em;
text-align: center;
border-right: 1px solid rgba(0, 0, 0, 0.2);
}
&.btn-lg {
padding-left: (@bs-height-lg + @padding-large-horizontal);
:first-child {
line-height: @bs-height-lg;
width: @bs-height-lg;
font-size: 1.8em;
}
}
&.btn-sm {
padding-left: (@bs-height-sm + @padding-small-horizontal);
:first-child {
line-height: @bs-height-sm;
width: @bs-height-sm;
font-size: 1.4em;
}
}
&.btn-xs {
padding-left: (@bs-height-xs + @padding-small-horizontal);
:first-child {
line-height: @bs-height-xs;
width: @bs-height-xs;
font-size: 1.2em;
}
}
}

.btn-social-icon {
.btn-social;
height: (@bs-height-base + 2);
width: (@bs-height-base + 2);
padding: 0;
:first-child {
border: none;
text-align: center;
width: 100%!important;
}
&.btn-lg {
height: @bs-height-lg;
width: @bs-height-lg;
padding-left: 0;
padding-right: 0;
}
&.btn-sm {
height: (@bs-height-sm + 2);
width: (@bs-height-sm + 2);
padding-left: 0;
padding-right: 0;
}
&.btn-xs {
height: (@bs-height-xs + 2);
width: (@bs-height-xs + 2);
padding-left: 0;
padding-right: 0;
}
}

.btn-social(@color-bg, @color: #fff) {
background-color: @color-bg;
.button-variant(@color, @color-bg, rgba(0,0,0,.2));
}


.btn-adn { .btn-social(#d87a68); }
.btn-bitbucket { .btn-social(#205081); }
.btn-dropbox { .btn-social(#1087dd); }
.btn-facebook { .btn-social(#3b5998); }
.btn-flickr { .btn-social(#ff0084); }
.btn-foursquare { .btn-social(#f94877); }
.btn-github { .btn-social(#444444); }
.btn-google-plus { .btn-social(#dd4b39); }
.btn-instagram { .btn-social(#3f729b); }
.btn-linkedin { .btn-social(#007bb6); }
.btn-microsoft { .btn-social(#2672ec); }
.btn-openid { .btn-social(#f7931e); }
.btn-pinterest { .btn-social(#cb2027); }
.btn-reddit { .btn-social(#eff7ff, #000); }
.btn-soundcloud { .btn-social(#ff5500); }
.btn-tumblr { .btn-social(#2c4762); }
.btn-twitter { .btn-social(#55acee); }
.btn-vimeo { .btn-social(#1ab7ea); }
.btn-vk { .btn-social(#587ea3); }
.btn-yahoo { .btn-social(#720e9e); }

+ 114
- 0
static/bower_components/bootstrap-social/bootstrap-social.scss View File

@@ -0,0 +1,114 @@
/*
* Social Buttons for Bootstrap
*
* Copyright 2013-2014 Panayiotis Lipiridis
* Licensed under the MIT License
*
* https://github.com/lipis/bootstrap-social
*/

$bs-height-base: ($line-height-computed + $padding-base-vertical * 2);
$bs-height-lg: (floor($font-size-large * $line-height-base) + $padding-large-vertical * 2);
$bs-height-sm: (floor($font-size-small * 1.5) + $padding-small-vertical * 2);
$bs-height-xs: (floor($font-size-small * 1.2) + $padding-small-vertical + 1);

.btn-social {
position: relative;
padding-left: ($bs-height-base + $padding-base-horizontal);
text-align: left;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
> :first-child {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: $bs-height-base;
line-height: ($bs-height-base + 2);
font-size: 1.6em;
text-align: center;
border-right: 1px solid rgba(0, 0, 0, 0.2);
}
&.btn-lg {
padding-left: ($bs-height-lg + $padding-large-horizontal);
:first-child {
line-height: $bs-height-lg;
width: $bs-height-lg;
font-size: 1.8em;
}
}
&.btn-sm {
padding-left: ($bs-height-sm + $padding-small-horizontal);
:first-child {
line-height: $bs-height-sm;
width: $bs-height-sm;
font-size: 1.4em;
}
}
&.btn-xs {
padding-left: ($bs-height-xs + $padding-small-horizontal);
:first-child {
line-height: $bs-height-xs;
width: $bs-height-xs;
font-size: 1.2em;
}
}
}

.btn-social-icon {
@extend .btn-social;
height: ($bs-height-base + 2);
width: ($bs-height-base + 2);
padding: 0;
:first-child {
border: none;
text-align: center;
width: 100%!important;
}
&.btn-lg {
height: $bs-height-lg;
width: $bs-height-lg;
padding-left: 0;
padding-right: 0;
}
&.btn-sm {
height: ($bs-height-sm + 2);
width: ($bs-height-sm + 2);
padding-left: 0;
padding-right: 0;
}
&.btn-xs {
height: ($bs-height-xs + 2);
width: ($bs-height-xs + 2);
padding-left: 0;
padding-right: 0;
}
}

@mixin btn-social($color-bg, $color: #fff) {
background-color: $color-bg;
@include button-variant($color, $color-bg, rgba(0,0,0,.2));
}


.btn-adn { @include btn-social(#d87a68); }
.btn-bitbucket { @include btn-social(#205081); }
.btn-dropbox { @include btn-social(#1087dd); }
.btn-facebook { @include btn-social(#3b5998); }
.btn-flickr { @include btn-social(#ff0084); }
.btn-foursquare { @include btn-social(#f94877); }
.btn-github { @include btn-social(#444444); }
.btn-google-plus { @include btn-social(#dd4b39); }
.btn-instagram { @include btn-social(#3f729b); }
.btn-linkedin { @include btn-social(#007bb6); }
.btn-microsoft { @include btn-social(#2672ec); }
.btn-openid { @include btn-social(#f7931e); }
.btn-pinterest { @include btn-social(#cb2027); }
.btn-reddit { @include btn-social(#eff7ff, #000); }
.btn-soundcloud { @include btn-social(#ff5500); }
.btn-tumblr { @include btn-social(#2c4762); }
.btn-twitter { @include btn-social(#55acee); }
.btn-vimeo { @include btn-social(#1ab7ea); }
.btn-vk { @include btn-social(#587ea3); }
.btn-yahoo { @include btn-social(#720e9e); }

+ 14
- 0
static/bower_components/bootstrap-social/bower.json View File

@@ -0,0 +1,14 @@
{
"name": "bootstrap-social",
"main": "bootstrap-social.css",
"licence": "MIT",
"ignore": [
"assets",
"index.html",
"LICENCE"
],
"dependencies": {
"bootstrap": "~3",
"font-awesome": "~4.2"
}
}

+ 47
- 0
static/bower_components/bootstrap/.bower.json View File

@@ -0,0 +1,47 @@
{
"name": "bootstrap",
"description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
"version": "3.3.2",
"keywords": [
"css",
"js",
"less",
"mobile-first",
"responsive",
"front-end",
"framework",
"web"
],
"homepage": "http://getbootstrap.com",
"main": [
"less/bootstrap.less",
"dist/css/bootstrap.css",
"dist/js/bootstrap.js",
"dist/fonts/glyphicons-halflings-regular.eot",
"dist/fonts/glyphicons-halflings-regular.svg",
"dist/fonts/glyphicons-halflings-regular.ttf",
"dist/fonts/glyphicons-halflings-regular.woff"
],
"ignore": [
"/.*",
"_config.yml",
"CNAME",
"composer.json",
"CONTRIBUTING.md",
"docs",
"js/tests",
"test-infra"
],
"dependencies": {
"jquery": ">= 1.9.1"
},
"_release": "3.3.2",
"_resolution": {
"type": "version",
"tag": "v3.3.2",
"commit": "bcf7dd38b5ab180256e2e4fb5da0369551b3f082"
},
"_source": "git://github.com/twbs/bootstrap.git",
"_target": "~3.3.1",
"_originalSource": "bootstrap"
}

+ 509
- 0
static/bower_components/bootstrap/Gruntfile.js View File

@@ -0,0 +1,509 @@
/*!
* Bootstrap's Gruntfile
* http://getbootstrap.com
* Copyright 2013-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/

module.exports = function (grunt) {
'use strict';

// Force use of Unix newlines
grunt.util.linefeed = '\n';

RegExp.quote = function (string) {
return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&');
};

var fs = require('fs');
var path = require('path');
var npmShrinkwrap = require('npm-shrinkwrap');
var generateGlyphiconsData = require('./grunt/bs-glyphicons-data-generator.js');
var BsLessdocParser = require('./grunt/bs-lessdoc-parser.js');
var getLessVarsData = function () {
var filePath = path.join(__dirname, 'less/variables.less');
var fileContent = fs.readFileSync(filePath, { encoding: 'utf8' });
var parser = new BsLessdocParser(fileContent);
return { sections: parser.parseFile() };
};
var generateRawFiles = require('./grunt/bs-raw-files-generator.js');
var generateCommonJSModule = require('./grunt/bs-commonjs-generator.js');
var configBridge = grunt.file.readJSON('./grunt/configBridge.json', { encoding: 'utf8' });

Object.keys(configBridge.paths).forEach(function (key) {
configBridge.paths[key].forEach(function (val, i, arr) {
arr[i] = path.join('./docs/assets', val);
});
});

// Project configuration.
grunt.initConfig({

// Metadata.
pkg: grunt.file.readJSON('package.json'),
banner: '/*!\n' +
' * Bootstrap v<%= pkg.version %> (<%= pkg.homepage %>)\n' +
' * Copyright 2011-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
' * Licensed under <%= pkg.license.type %> (<%= pkg.license.url %>)\n' +
' */\n',
jqueryCheck: configBridge.config.jqueryCheck.join('\n'),
jqueryVersionCheck: configBridge.config.jqueryVersionCheck.join('\n'),

// Task configuration.
clean: {
dist: 'dist',
docs: 'docs/dist'
},

jshint: {
options: {
jshintrc: 'js/.jshintrc'
},
grunt: {
options: {
jshintrc: 'grunt/.jshintrc'
},
src: ['Gruntfile.js', 'grunt/*.js']
},
core: {
src: 'js/*.js'
},
test: {
options: {
jshintrc: 'js/tests/unit/.jshintrc'
},
src: 'js/tests/unit/*.js'
},
assets: {
src: ['docs/assets/js/src/*.js', 'docs/assets/js/*.js', '!docs/assets/js/*.min.js']
}
},

jscs: {
options: {
config: 'js/.jscsrc'
},
grunt: {
src: '<%= jshint.grunt.src %>'
},
core: {
src: '<%= jshint.core.src %>'
},
test: {
src: '<%= jshint.test.src %>'
},
assets: {
options: {
requireCamelCaseOrUpperCaseIdentifiers: null
},
src: '<%= jshint.assets.src %>'
}
},

concat: {
options: {
banner: '<%= banner %>\n<%= jqueryCheck %>\n<%= jqueryVersionCheck %>',
stripBanners: false
},
bootstrap: {
src: [
'js/transition.js',
'js/alert.js',
'js/button.js',
'js/carousel.js',
'js/collapse.js',
'js/dropdown.js',
'js/modal.js',
'js/tooltip.js',
'js/popover.js',
'js/scrollspy.js',
'js/tab.js',
'js/affix.js'
],
dest: 'dist/js/<%= pkg.name %>.js'
}
},

uglify: {
options: {
preserveComments: 'some'
},
core: {
src: '<%= concat.bootstrap.dest %>',
dest: 'dist/js/<%= pkg.name %>.min.js'
},
customize: {
src: configBridge.paths.customizerJs,
dest: 'docs/assets/js/customize.min.js'
},
docsJs: {
src: configBridge.paths.docsJs,
dest: 'docs/assets/js/docs.min.js'
}
},

qunit: {
options: {
inject: 'js/tests/unit/phantom.js'
},
files: 'js/tests/index.html'
},

less: {
compileCore: {
options: {
strictMath: true,
sourceMap: true,
outputSourceFiles: true,
sourceMapURL: '<%= pkg.name %>.css.map',
sourceMapFilename: 'dist/css/<%= pkg.name %>.css.map'
},
src: 'less/bootstrap.less',
dest: 'dist/css/<%= pkg.name %>.css'
},
compileTheme: {
options: {
strictMath: true,
sourceMap: true,
outputSourceFiles: true,
sourceMapURL: '<%= pkg.name %>-theme.css.map',
sourceMapFilename: 'dist/css/<%= pkg.name %>-theme.css.map'
},
src: 'less/theme.less',
dest: 'dist/css/<%= pkg.name %>-theme.css'
}
},

autoprefixer: {
options: {
browsers: configBridge.config.autoprefixerBrowsers
},
core: {
options: {
map: true
},
src: 'dist/css/<%= pkg.name %>.css'
},
theme: {
options: {
map: true
},
src: 'dist/css/<%= pkg.name %>-theme.css'
},
docs: {
src: 'docs/assets/css/src/docs.css'
},
examples: {
expand: true,
cwd: 'docs/examples/',
src: ['**/*.css'],
dest: 'docs/examples/'
}
},

csslint: {
options: {
csslintrc: 'less/.csslintrc'
},
dist: [
'dist/css/bootstrap.css',
'dist/css/bootstrap-theme.css'
],
examples: [
'docs/examples/**/*.css'
],
docs: {
options: {
ids: false,
'overqualified-elements': false
},
src: 'docs/assets/css/src/docs.css'
}
},

cssmin: {
options: {
compatibility: 'ie8',
keepSpecialComments: '*',
advanced: false
},
minifyCore: {
src: 'dist/css/<%= pkg.name %>.css',
dest: 'dist/css/<%= pkg.name %>.min.css'
},
minifyTheme: {
src: 'dist/css/<%= pkg.name %>-theme.css',
dest: 'dist/css/<%= pkg.name %>-theme.min.css'
},
docs: {
src: [
'docs/assets/css/src/docs.css',
'docs/assets/css/src/pygments-manni.css'
],
dest: 'docs/assets/css/docs.min.css'
}
},

usebanner: {
options: {
position: 'top',
banner: '<%= banner %>'
},
files: {
src: 'dist/css/*.css'
}
},

csscomb: {
options: {
config: 'less/.csscomb.json'
},
dist: {
expand: true,
cwd: 'dist/css/',
src: ['*.css', '!*.min.css'],
dest: 'dist/css/'
},
examples: {
expand: true,
cwd: 'docs/examples/',
src: '**/*.css',
dest: 'docs/examples/'
},
docs: {
src: 'docs/assets/css/src/docs.css',
dest: 'docs/assets/css/src/docs.css'
}
},

copy: {
fonts: {
src: 'fonts/*',
dest: 'dist/'
},
docs: {
src: 'dist/*/*',
dest: 'docs/'
}
},

connect: {
server: {
options: {
port: 3000,
base: '.'
}
}
},

jekyll: {
options: {
config: '_config.yml'
},
docs: {},
github: {
options: {
raw: 'github: true'
}
}
},

jade: {
options: {
pretty: true,
data: getLessVarsData
},
customizerVars: {
src: 'docs/_jade/customizer-variables.jade',
dest: 'docs/_includes/customizer-variables.html'
},
customizerNav: {
src: 'docs/_jade/customizer-nav.jade',
dest: 'docs/_includes/nav/customize.html'
}
},

validation: {
options: {
charset: 'utf-8',
doctype: 'HTML5',
failHard: true,
reset: true,
relaxerror: [
'Element img is missing required attribute src.',
'Attribute autocomplete not allowed on element input at this point.',
'Attribute autocomplete not allowed on element button at this point.',
'Bad value separator for attribute role on element li.'
]
},
files: {
src: '_gh_pages/**/*.html'
}
},

watch: {
src: {
files: '<%= jshint.core.src %>',
tasks: ['jshint:src', 'qunit', 'concat']
},
test: {
files: '<%= jshint.test.src %>',
tasks: ['jshint:test', 'qunit']
},
less: {
files: 'less/**/*.less',
tasks: 'less'
}
},

sed: {
versionNumber: {
pattern: (function () {
var old = grunt.option('oldver');
return old ? RegExp.quote(old) : old;
})(),
replacement: grunt.option('newver'),
recursive: true
}
},

'saucelabs-qunit': {
all: {
options: {
build: process.env.TRAVIS_JOB_ID,
throttled: 10,
maxRetries: 3,
maxPollRetries: 4,
urls: ['http://127.0.0.1:3000/js/tests/index.html'],
browsers: grunt.file.readYAML('grunt/sauce_browsers.yml')
}
}
},

exec: {
npmUpdate: {
command: 'npm update'
}
},

compress: {
main: {
options: {
archive: 'bootstrap-<%= pkg.version %>-dist.zip',
mode: 'zip',
level: 9,
pretty: true
},
files: [
{
expand: true,
cwd: 'dist/',
src: ['**'],
dest: 'bootstrap-<%= pkg.version %>-dist'
}
]
}
}

});


// These plugins provide necessary tasks.
require('load-grunt-tasks')(grunt, { scope: 'devDependencies' });
require('time-grunt')(grunt);

// Docs HTML validation task
grunt.registerTask('validate-html', ['jekyll:docs', 'validation']);

var runSubset = function (subset) {
return !process.env.TWBS_TEST || process.env.TWBS_TEST === subset;
};
var isUndefOrNonZero = function (val) {
return val === undefined || val !== '0';
};

// Test task.
var testSubtasks = [];
// Skip core tests if running a different subset of the test suite
if (runSubset('core') &&
// Skip core tests if this is a Savage build
process.env.TRAVIS_REPO_SLUG !== 'twbs-savage/bootstrap') {
testSubtasks = testSubtasks.concat(['dist-css', 'dist-js', 'csslint:dist', 'test-js', 'docs']);
}
// Skip HTML validation if running a different subset of the test suite
if (runSubset('validate-html') &&
// Skip HTML5 validator on Travis when [skip validator] is in the commit message
isUndefOrNonZero(process.env.TWBS_DO_VALIDATOR)) {
testSubtasks.push('validate-html');
}
// Only run Sauce Labs tests if there's a Sauce access key
if (typeof process.env.SAUCE_ACCESS_KEY !== 'undefined' &&
// Skip Sauce if running a different subset of the test suite
runSubset('sauce-js-unit') &&
// Skip Sauce on Travis when [skip sauce] is in the commit message
isUndefOrNonZero(process.env.TWBS_DO_SAUCE)) {
testSubtasks.push('connect');
testSubtasks.push('saucelabs-qunit');
}
grunt.registerTask('test', testSubtasks);
grunt.registerTask('test-js', ['jshint:core', 'jshint:test', 'jshint:grunt', 'jscs:core', 'jscs:test', 'jscs:grunt', 'qunit']);

// JS distribution task.
grunt.registerTask('dist-js', ['concat', 'uglify:core', 'commonjs']);

// CSS distribution task.
grunt.registerTask('less-compile', ['less:compileCore', 'less:compileTheme']);
grunt.registerTask('dist-css', ['less-compile', 'autoprefixer:core', 'autoprefixer:theme', 'usebanner', 'csscomb:dist', 'cssmin:minifyCore', 'cssmin:minifyTheme']);

// Full distribution task.
grunt.registerTask('dist', ['clean:dist', 'dist-css', 'copy:fonts', 'dist-js']);

// Default task.
grunt.registerTask('default', ['clean:dist', 'copy:fonts', 'test']);

// Version numbering task.
// grunt change-version-number --oldver=A.B.C --newver=X.Y.Z
// This can be overzealous, so its changes should always be manually reviewed!
grunt.registerTask('change-version-number', 'sed');

grunt.registerTask('build-glyphicons-data', function () { generateGlyphiconsData.call(this, grunt); });

// task for building customizer
grunt.registerTask('build-customizer', ['build-customizer-html', 'build-raw-files']);
grunt.registerTask('build-customizer-html', 'jade');
grunt.registerTask('build-raw-files', 'Add scripts/less files to customizer.', function () {
var banner = grunt.template.process('<%= banner %>');
generateRawFiles(grunt, banner);
});

grunt.registerTask('commonjs', 'Generate CommonJS entrypoint module in dist dir.', function () {
var srcFiles = grunt.config.get('concat.bootstrap.src');
var destFilepath = 'dist/js/npm.js';
generateCommonJSModule(grunt, srcFiles, destFilepath);
});

// Docs task.
grunt.registerTask('docs-css', ['autoprefixer:docs', 'autoprefixer:examples', 'csscomb:docs', 'csscomb:examples', 'cssmin:docs']);
grunt.registerTask('lint-docs-css', ['csslint:docs', 'csslint:examples']);
grunt.registerTask('docs-js', ['uglify:docsJs', 'uglify:customize']);
grunt.registerTask('lint-docs-js', ['jshint:assets', 'jscs:assets']);
grunt.registerTask('docs', ['docs-css', 'lint-docs-css', 'docs-js', 'lint-docs-js', 'clean:docs', 'copy:docs', 'build-glyphicons-data', 'build-customizer']);

grunt.registerTask('prep-release', ['jekyll:github', 'compress']);

// Task for updating the cached npm packages used by the Travis build (which are controlled by test-infra/npm-shrinkwrap.json).
// This task should be run and the updated file should be committed whenever Bootstrap's dependencies change.
grunt.registerTask('update-shrinkwrap', ['exec:npmUpdate', '_update-shrinkwrap']);
grunt.registerTask('_update-shrinkwrap', function () {
var done = this.async();
npmShrinkwrap({ dev: true, dirname: __dirname }, function (err) {
if (err) {
grunt.fail.warn(err);
}
var dest = 'test-infra/npm-shrinkwrap.json';
fs.renameSync('npm-shrinkwrap.json', dest);
grunt.log.writeln('File ' + dest.cyan + ' updated.');
done();
});
});
};

+ 21
- 0
static/bower_components/bootstrap/LICENSE View File

@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2011-2015 Twitter, Inc

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

+ 132
- 0
static/bower_components/bootstrap/README.md View File

@@ -0,0 +1,132 @@
# [Bootstrap](http://getbootstrap.com)
![Bower version](https://img.shields.io/bower/v/bootstrap.svg?style=flat)
[![npm version](https://img.shields.io/npm/v/bootstrap.svg?style=flat)](https://www.npmjs.com/package/bootstrap)
[![Build Status](https://img.shields.io/travis/twbs/bootstrap/master.svg?style=flat)](https://travis-ci.org/twbs/bootstrap)
[![devDependency Status](https://img.shields.io/david/dev/twbs/bootstrap.svg?style=flat)](https://david-dm.org/twbs/bootstrap#info=devDependencies)
[![Selenium Test Status](https://saucelabs.com/browser-matrix/bootstrap.svg)](https://saucelabs.com/u/bootstrap)

Bootstrap is a sleek, intuitive, and powerful front-end framework for faster and easier web development, created by [Mark Otto](https://twitter.com/mdo) and [Jacob Thornton](https://twitter.com/fat), and maintained by the [core team](https://github.com/orgs/twbs/people) with the massive support and involvement of the community.

To get started, check out <http://getbootstrap.com>!

## Table of contents

- [Quick start](#quick-start)
- [Bugs and feature requests](#bugs-and-feature-requests)
- [Documentation](#documentation)
- [Contributing](#contributing)
- [Community](#community)
- [Versioning](#versioning)
- [Creators](#creators)
- [Copyright and license](#copyright-and-license)

## Quick start

Four quick start options are available:

- [Download the latest release](https://github.com/twbs/bootstrap/archive/v3.3.2.zip).
- Clone the repo: `git clone https://github.com/twbs/bootstrap.git`.
- Install with [Bower](http://bower.io): `bower install bootstrap`.
- Install with [npm](https://www.npmjs.org): `npm install bootstrap`.

Read the [Getting started page](http://getbootstrap.com/getting-started/) for information on the framework contents, templates and examples, and more.

### What's included

Within the download you'll find the following directories and files, logically grouping common assets and providing both compiled and minified variations. You'll see something like this:

```
bootstrap/
├── css/
│ ├── bootstrap.css
│ ├── bootstrap.css.map
│ ├── bootstrap.min.css
│ ├── bootstrap-theme.css
│ ├── bootstrap-theme.css.map
│ └── bootstrap-theme.min.css
├── js/
│ ├── bootstrap.js
│ └── bootstrap.min.js
└── fonts/
├── glyphicons-halflings-regular.eot
├── glyphicons-halflings-regular.svg
├── glyphicons-halflings-regular.ttf
├── glyphicons-halflings-regular.woff
└── glyphicons-halflings-regular.woff2
```

We provide compiled CSS and JS (`bootstrap.*`), as well as compiled and minified CSS and JS (`bootstrap.min.*`). CSS [source maps](https://developers.google.com/chrome-developer-tools/docs/css-preprocessors) (`bootstrap.*.map`) are available for use with certain browsers' developer tools. Fonts from Glyphicons are included, as is the optional Bootstrap theme.



## Bugs and feature requests

Have a bug or a feature request? Please first read the [issue guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md#using-the-issue-tracker) and search for existing and closed issues. If your problem or idea is not addressed yet, [please open a new issue](https://github.com/twbs/bootstrap/issues/new).


## Documentation

Bootstrap's documentation, included in this repo in the root directory, is built with [Jekyll](http://jekyllrb.com) and publicly hosted on GitHub Pages at <http://getbootstrap.com>. The docs may also be run locally.

### Running documentation locally

1. If necessary, [install Jekyll](http://jekyllrb.com/docs/installation) (requires v2.5.x).
- **Windows users:** Read [this unofficial guide](http://jekyll-windows.juthilo.com/) to get Jekyll up and running without problems.
2. Install the Ruby-based syntax highlighter, [Rouge](https://github.com/jneen/rouge), with `gem install rouge`.
3. From the root `/bootstrap` directory, run `jekyll serve` in the command line.
4. Open <http://localhost:9001> in your browser, and voilà.

Learn more about using Jekyll by reading its [documentation](http://jekyllrb.com/docs/home/).

### Documentation for previous releases

Documentation for v2.3.2 has been made available for the time being at <http://getbootstrap.com/2.3.2/> while folks transition to Bootstrap 3.

[Previous releases](https://github.com/twbs/bootstrap/releases) and their documentation are also available for download.



## Contributing

Please read through our [contributing guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md). Included are directions for opening issues, coding standards, and notes on development.

Moreover, if your pull request contains JavaScript patches or features, you must include relevant unit tests. All HTML and CSS should conform to the [Code Guide](https://github.com/mdo/code-guide), maintained by [Mark Otto](https://github.com/mdo).

Editor preferences are available in the [editor config](https://github.com/twbs/bootstrap/blob/master/.editorconfig) for easy use in common text editors. Read more and download plugins at <http://editorconfig.org>.



## Community

Keep track of development and community news.

- Follow [@twbootstrap on Twitter](https://twitter.com/twbootstrap).
- Read and subscribe to [The Official Bootstrap Blog](http://blog.getbootstrap.com).
- Chat with fellow Bootstrappers in IRC. On the `irc.freenode.net` server, in the `##bootstrap` channel.
- Implementation help may be found at Stack Overflow (tagged [`twitter-bootstrap-3`](http://stackoverflow.com/questions/tagged/twitter-bootstrap-3)).



## Versioning

For transparency into our release cycle and in striving to maintain backward compatibility, Bootstrap is maintained under [the Semantic Versioning guidelines](http://semver.org/). Sometimes we screw up, but we'll adhere to those rules whenever possible.



## Creators

**Mark Otto**

- <https://twitter.com/mdo>
- <https://github.com/mdo>

**Jacob Thornton**

- <https://twitter.com/fat>
- <https://github.com/fat>



## Copyright and license

Code and documentation copyright 2011-2015 Twitter, Inc. Code released under [the MIT license](https://github.com/twbs/bootstrap/blob/master/LICENSE). Docs released under [Creative Commons](https://github.com/twbs/bootstrap/blob/master/docs/LICENSE).

+ 38
- 0
static/bower_components/bootstrap/bower.json View File

@@ -0,0 +1,38 @@
{
"name": "bootstrap",
"description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
"version": "3.3.2",
"keywords": [
"css",
"js",
"less",
"mobile-first",
"responsive",
"front-end",
"framework",
"web"
],
"homepage": "http://getbootstrap.com",
"main": [
"less/bootstrap.less",
"dist/css/bootstrap.css",
"dist/js/bootstrap.js",
"dist/fonts/glyphicons-halflings-regular.eot",
"dist/fonts/glyphicons-halflings-regular.svg",
"dist/fonts/glyphicons-halflings-regular.ttf",
"dist/fonts/glyphicons-halflings-regular.woff"
],
"ignore": [
"/.*",
"_config.yml",
"CNAME",
"composer.json",
"CONTRIBUTING.md",
"docs",
"js/tests",
"test-infra"
],
"dependencies": {
"jquery": ">= 1.9.1"
}
}

+ 476
- 0
static/bower_components/bootstrap/dist/css/bootstrap-theme.css View File

@@ -0,0 +1,476 @@
/*!
* Bootstrap v3.3.2 (http://getbootstrap.com)
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/

.btn-default,
.btn-primary,
.btn-success,
.btn-info,
.btn-warning,
.btn-danger {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
}
.btn-default:active,
.btn-primary:active,
.btn-success:active,
.btn-info:active,
.btn-warning:active,
.btn-danger:active,
.btn-default.active,
.btn-primary.active,
.btn-success.active,
.btn-info.active,
.btn-warning.active,
.btn-danger.active {
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
}
.btn-default .badge,
.btn-primary .badge,
.btn-success .badge,
.btn-info .badge,
.btn-warning .badge,
.btn-danger .badge {
text-shadow: none;
}
.btn:active,
.btn.active {
background-image: none;
}
.btn-default {
text-shadow: 0 1px 0 #fff;
background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #dbdbdb;
border-color: #ccc;
}
.btn-default:hover,
.btn-default:focus {
background-color: #e0e0e0;
background-position: 0 -15px;
}
.btn-default:active,
.btn-default.active {
background-color: #e0e0e0;
border-color: #dbdbdb;
}
.btn-default.disabled,
.btn-default:disabled,
.btn-default[disabled] {
background-color: #e0e0e0;
background-image: none;
}
.btn-primary {
background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);
background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));
background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #245580;
}
.btn-primary:hover,
.btn-primary:focus {
background-color: #265a88;
background-position: 0 -15px;
}
.btn-primary:active,
.btn-primary.active {
background-color: #265a88;
border-color: #245580;
}
.btn-primary.disabled,
.btn-primary:disabled,
.btn-primary[disabled] {
background-color: #265a88;
background-image: none;
}
.btn-success {
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);