From 53ddf5fab484cb54eeb4b364118249c866c2d644 Mon Sep 17 00:00:00 2001 From: Patrick McDonagh Date: Wed, 7 Dec 2016 15:02:18 -0600 Subject: [PATCH] Initial framework for Pyramid --- .gitignore | 4 + pyr_test/hp_webserver/development.ini | 49 ++++ pyr_test/hp_webserver/poconsole/__init__.py | 35 +++ .../hp_webserver/poconsole/initalize_db.py | 61 +++++ pyr_test/hp_webserver/poconsole/models.py | 221 ++++++++++++++++++ pyr_test/hp_webserver/poconsole/tests.py | 0 pyr_test/hp_webserver/poconsole/views.py | 128 ++++++++++ pyr_test/hp_webserver/setup.py | 20 ++ 8 files changed, 518 insertions(+) create mode 100644 pyr_test/hp_webserver/development.ini create mode 100644 pyr_test/hp_webserver/poconsole/__init__.py create mode 100644 pyr_test/hp_webserver/poconsole/initalize_db.py create mode 100644 pyr_test/hp_webserver/poconsole/models.py create mode 100644 pyr_test/hp_webserver/poconsole/tests.py create mode 100644 pyr_test/hp_webserver/poconsole/views.py create mode 100644 pyr_test/hp_webserver/setup.py diff --git a/.gitignore b/.gitignore index 558f493..b6ba24a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,7 @@ sails/.tmp .remote-sync.json database.db venv/ +.vscode/ +pyr_test/env/lib/python2.7/site-packages/pyramid/tests/test_scaffolds/fixture_scaffold/development.ini_tmpl +pyr_test/env/ +pyr_test/hp_webserver/poconsole.egg-info/ diff --git a/pyr_test/hp_webserver/development.ini b/pyr_test/hp_webserver/development.ini new file mode 100644 index 0000000..1daa7d7 --- /dev/null +++ b/pyr_test/hp_webserver/development.ini @@ -0,0 +1,49 @@ +[app:main] +use = egg:poconsole +pyramid.reload_templates = true +pyramid.includes = + pyramid_debugtoolbar + pyramid_tm + +sqlalchemy.url = sqlite:///%(here)s/poconsole.sqlite + +[server:main] +use = egg:pyramid#wsgiref +host = 0.0.0.0 +port = 6543 + +# Begin logging configuration + +[loggers] +keys = root, poconsole, sqlalchemy.engine.base.Engine + +[logger_poconsole] +level = DEBUG +handlers = +qualname = poconsole + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = INFO +handlers = console + +[logger_sqlalchemy.engine.base.Engine] +level = INFO +handlers = +qualname = sqlalchemy.engine.base.Engine + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s + +# End logging configuration \ No newline at end of file diff --git a/pyr_test/hp_webserver/poconsole/__init__.py b/pyr_test/hp_webserver/poconsole/__init__.py new file mode 100644 index 0000000..660907a --- /dev/null +++ b/pyr_test/hp_webserver/poconsole/__init__.py @@ -0,0 +1,35 @@ +from pyramid.config import Configurator + +from sqlalchemy import engine_from_config + +from .models import DBSession, Base + +def main(global_config, **settings): + engine = engine_from_config(settings, 'sqlalchemy.') + DBSession.configure(bind=engine) + Base.metadata.bind = engine + + config = Configurator(settings=settings, + root_factory='poconsole.models.Root') + config.include('pyramid_chameleon') + + # Configs + config.add_route('configs', '/api/configs') + config.add_route('config', '/api/configs/{_id}') + + # Configs + config.add_route('configs', '/api/configs') + config.add_route('config', '/api/configs/{_id}') + + # Device Types + config.add_route('device_types', '/api/device_types') + config.add_route('device_type', '/api/device_types/{_id}') + + + config.add_route('wiki_view', '/') + config.add_route('wikipage_add', '/add') + config.add_route('wikipage_view', '/{uid}') + config.add_route('wikipage_edit', '/{uid}/edit') + config.add_static_view('deform_static', 'deform:static/') + config.scan('.views') + return config.make_wsgi_app() \ No newline at end of file diff --git a/pyr_test/hp_webserver/poconsole/initalize_db.py b/pyr_test/hp_webserver/poconsole/initalize_db.py new file mode 100644 index 0000000..7962420 --- /dev/null +++ b/pyr_test/hp_webserver/poconsole/initalize_db.py @@ -0,0 +1,61 @@ +import os +import sys +import transaction + +from sqlalchemy import engine_from_config + +from pyramid.paster import ( + get_appsettings, + setup_logging, + ) + +from .models import ( + DBSession, + Config, + Device_type, + Device, + Doc, + Tag, + Tag_val, + Card, + GaugeOffVal, + WellTest, + Note, + EventConfig, + Event, + RunStatus, + FluidShot, + BackupRestore, + Base, + ) + + +def usage(argv): + cmd = os.path.basename(argv[0]) + print('usage: %s \n' + '(example: "%s development.ini")' % (cmd, cmd)) + sys.exit(1) + + +def main(argv=sys.argv): + if len(argv) != 2: + usage(argv) + config_uri = argv[1] + setup_logging(config_uri) + settings = get_appsettings(config_uri) + engine = engine_from_config(settings, 'sqlalchemy.') + DBSession.configure(bind=engine) + Base.metadata.create_all(engine) + with transaction.manager: + # Device Type Seeds + device_type_CLX = Device_type(device_type='CLX') + device_type_u800 = Device_type(device_type='Micro800') + device_type_E300 = Device_type(device_type='E300') + + DBSession.add(device_type_CLX) + DBSession.add(device_type_u800) + DBSession.add(device_type_E300) + + # Device Seeds + main_plc = Device(device_type_id=1, address="192.168.1.10") + DBSession.add(main_plc) diff --git a/pyr_test/hp_webserver/poconsole/models.py b/pyr_test/hp_webserver/poconsole/models.py new file mode 100644 index 0000000..318e388 --- /dev/null +++ b/pyr_test/hp_webserver/poconsole/models.py @@ -0,0 +1,221 @@ +from pyramid.security import Allow, Everyone +from datetime import datetime + +from sqlalchemy import ( + Column, + Integer, + Text, + String, + Float, + DateTime, + ForeignKey, + ) + +from sqlalchemy.ext.declarative import declarative_base + +from sqlalchemy.orm import ( + scoped_session, + sessionmaker, + relationship + ) + +from zope.sqlalchemy import ZopeTransactionExtension + +DBSession = scoped_session( + sessionmaker(extension=ZopeTransactionExtension())) +Base = declarative_base() + + +# class Page(Base): +# __tablename__ = 'wikipages' +# uid = Column(Integer, primary_key=True) +# title = Column(Text, unique=True) +# body = Column(Text) + +class Config(Base): + __tablename__ = "configs" + _id = Column(Integer, primary_key=True) + parameter = Column(String(100), unique=True) + val = Column(String(100), unique=True) + created_on = Column(DateTime(), default=datetime.utcnow) + updated_on = Column(DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow) + + +class Device_type(Base): + __tablename__ = "device_types" + _id = Column(Integer, primary_key=True) + device_type = Column(String(64)) + created_on = Column(DateTime(), default=datetime.utcnow) + updated_on = Column(DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow) + + +class Device(Base): + __tablename__ = "devices" + _id = Column(Integer, primary_key=True) + device_type_id = Column(Integer, ForeignKey('device_types._id')) + device_type = relationship(Device_type, primaryjoin=device_type_id == Device_type._id) + address = Column(String(256)) + created_on = Column(DateTime(), default=datetime.utcnow) + updated_on = Column(DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow) + + +class Doc(Base): + __tablename__ = "docs" + _id = Column(Integer, primary_key=True) + name = Column(String(256)) + created_on = Column(DateTime(), default=datetime.utcnow) + updated_on = Column(DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow) + + +class Tag(Base): + __tablename__ = "tags" + _id = Column(Integer, primary_key=True) + name = Column(String(64)) + tag = Column(String(128)) + tag_category = Column(String(128)) + device_id = Column(Integer, ForeignKey('devices._id')) + device = relationship(Device) + description = Column(String(64)) + data_type = Column(String(64)) + change_threshold = Column(Float) + guarantee_sec = Column(Integer) + map_function = Column(String(64)) + units = Column(String(10)) + min_expected = Column(Float) + max_expected = Column(Float) + created_on = Column(DateTime(), default=datetime.utcnow) + updated_on = Column(DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow) + + +class Tag_val(Base): + __tablename__ = "tag_vals" + _id = Column(Integer, primary_key=True) + tag_id = Column(Integer, ForeignKey('tags._id')) + tag = relationship(Tag) + value = Column(Float) + created_on = Column(DateTime(), default=datetime.utcnow) + updated_on = Column(DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow) + + +class Card(Base): + __tablename__ = "cards" + _id = Column(Integer, primary_key=True) + stroke_type = Column(String(32)) + stroke_number = Column(Integer) + surf_pos = Column(Text) + surf_lod = Column(Text) + down_pos = Column(Text) + down_lod = Column(Text) + created_on = Column(DateTime(), default=datetime.utcnow) + updated_on = Column(DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow) + + +class GaugeOffVal(Base): + __tablename__ = "gauge_off" + _id = Column(Integer, primary_key=True) + spm_average = Column(Float) + downhole_gross_stroke_average = Column(Float) + downhole_net_stroke_average = Column(Float) + electricity_cost_total = Column(Float) + fluid_level_average = Column(Float) + full_card_production_total = Column(Float) + inflow_rate_average = Column(Float) + kWh_used_total = Column(Float) + kWh_regen_total = Column(Float) + lifting_cost_average = Column(Float) + peak_pr_load = Column(Float) + min_pr_load = Column(Float) + percent_run = Column(Float) + polished_rod_hp_average = Column(Float) + pump_hp_average = Column(Float) + production_total = Column(Float) + pump_intake_pressure_average = Column(Float) + surface_stroke_length_average = Column(Float) + tubing_movement_average = Column(Float) + created_on = Column(DateTime(), default=datetime.utcnow) + updated_on = Column(DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow) + + +class WellTest(Base): + __tablename__ = "well_tests" + _id = Column(Integer, primary_key=True) + duration_hours = Column(Float) + volume_h2o_actual = Column(Float) + volume_oil_actual = Column(Float) + volume_gas_actual = Column(Float) + volume_h2o_projected = Column(Float) + volume_oil_projected = Column(Float) + volume_gas_projected = Column(Float) + api_gravity_oil = Column(Float) + spc_gravity_h2o = Column(Float) + created_on = Column(DateTime(), default=datetime.utcnow) + updated_on = Column(DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow) + + +class Note(Base): + __tablename__ = "notes" + _id = Column(Integer, primary_key=True) + note_text = Column(String(256)) + author = Column(String(128)) + created_on = Column(DateTime(), default=datetime.utcnow) + updated_on = Column(DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow) + + +class EventConfig(Base): + __tablename__ = "event_configs" + _id = Column(Integer, primary_key=True) + name = Column(String(64)) + event_type = Column(String(64)) + tag = Column(String(128)) + condition = Column(String(64)) + device_id = Column(Integer, ForeignKey('devices._id')) + device = relationship(Device) + created_on = Column(DateTime(), default=datetime.utcnow) + updated_on = Column(DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow) + + +class Event(Base): + __tablename__ = "events" + _id = Column(Integer, primary_key=True) + event_id = Column(Integer, ForeignKey('event_configs._id')) + event = relationship(EventConfig) + event_type = Column(String(64)) + event_condition = Column(String(64)) + created_on = Column(DateTime(), default=datetime.utcnow) + updated_on = Column(DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow) + + +class RunStatus(Base): + __tablename__ = "run_status_log" + _id = Column(Integer, primary_key=True) + run_status = Column(String(64)) + created_on = Column(DateTime(), default=datetime.utcnow) + updated_on = Column(DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow) + + +class FluidShot(Base): + __tablename__ = "fluid_shots" + _id = Column(Integer, primary_key=True) + pump_intake_pressure = Column(Float) + created_on = Column(DateTime(), default=datetime.utcnow) + updated_on = Column(DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow) + + +class BackupRestore(Base): + __tablename__ = "backup_restore" + _id = Column(Integer, primary_key=True) + tag = Column(String(128)) + tag_type = Column(String(128)) + device_id = Column(Integer, ForeignKey('devices._id')) + device = relationship(Device) + value = Column(String(128)) + created_on = Column(DateTime(), default=datetime.utcnow) + updated_on = Column(DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow) + + +class Root(object): + __acl__ = [(Allow, Everyone, 'view'), + (Allow, 'group:editors', 'edit')] + + def __init__(self, request): + pass diff --git a/pyr_test/hp_webserver/poconsole/tests.py b/pyr_test/hp_webserver/poconsole/tests.py new file mode 100644 index 0000000..e69de29 diff --git a/pyr_test/hp_webserver/poconsole/views.py b/pyr_test/hp_webserver/poconsole/views.py new file mode 100644 index 0000000..5aa2fc5 --- /dev/null +++ b/pyr_test/hp_webserver/poconsole/views.py @@ -0,0 +1,128 @@ +import colander +import deform.widget + +from pyramid.httpexceptions import HTTPFound +from pyramid.view import view_config + +from .models import ( + DBSession, + Config, + Device_type, + Device, + Doc, + Tag, + Tag_val, + Card, + GaugeOffVal, + WellTest, + Note, + EventConfig, + Event, + RunStatus, + FluidShot, + BackupRestore +) + + +class WikiPage(colander.MappingSchema): + title = colander.SchemaNode(colander.String()) + body = colander.SchemaNode( + colander.String(), + widget=deform.widget.RichTextWidget() + ) + +class ConfigCol(colander.MappingSchema): + parameter = colander.SchemaNode(colander.string()) + val = colander.SchemaNode(colander.string()) + + +class ConfigViews(object): + def __init__(self, request): + self.request = request + + @view_config(route_name='config', renderer='json') + def get_config(self): + id = int(self.request.matchdict['id']) + config = DBSession.query(Config).filter_by(_id=id).one() + return dict(config=config) + + +class WikiViews(object): + def __init__(self, request): + self.request = request + + @property + def wiki_form(self): + schema = WikiPage() + return deform.Form(schema, buttons=('submit',)) + + @property + def reqts(self): + return self.wiki_form.get_widget_resources() + + @view_config(route_name='wiki_view', renderer='wiki_view.pt') + def wiki_view(self): + pages = DBSession.query(Page).order_by(Page.title) + return dict(title='Wiki View', pages=pages) + + @view_config(route_name='wikipage_add', + renderer='wikipage_addedit.pt') + def wikipage_add(self): + form = self.wiki_form.render() + + if 'submit' in self.request.params: + controls = self.request.POST.items() + try: + appstruct = self.wiki_form.validate(controls) + except deform.ValidationFailure as e: + # Form is NOT valid + return dict(form=e.render()) + + # Add a new page to the database + new_title = appstruct['title'] + new_body = appstruct['body'] + DBSession.add(Page(title=new_title, body=new_body)) + + # Get the new ID and redirect + page = DBSession.query(Page).filter_by(title=new_title).one() + new_uid = page.uid + + url = self.request.route_url('wikipage_view', uid=new_uid) + return HTTPFound(url) + + return dict(form=form) + + + @view_config(route_name='wikipage_view', renderer='wikipage_view.pt') + def wikipage_view(self): + uid = int(self.request.matchdict['uid']) + page = DBSession.query(Page).filter_by(uid=uid).one() + return dict(page=page) + + + @view_config(route_name='wikipage_edit', + renderer='wikipage_addedit.pt') + def wikipage_edit(self): + uid = int(self.request.matchdict['uid']) + page = DBSession.query(Page).filter_by(uid=uid).one() + + wiki_form = self.wiki_form + + if 'submit' in self.request.params: + controls = self.request.POST.items() + try: + appstruct = wiki_form.validate(controls) + except deform.ValidationFailure as e: + return dict(page=page, form=e.render()) + + # Change the content and redirect to the view + page.title = appstruct['title'] + page.body = appstruct['body'] + url = self.request.route_url('wikipage_view', uid=uid) + return HTTPFound(url) + + form = self.wiki_form.render(dict( + uid=page.uid, title=page.title, body=page.body) + ) + + return dict(page=page, form=form) \ No newline at end of file diff --git a/pyr_test/hp_webserver/setup.py b/pyr_test/hp_webserver/setup.py new file mode 100644 index 0000000..ed20585 --- /dev/null +++ b/pyr_test/hp_webserver/setup.py @@ -0,0 +1,20 @@ +from setuptools import setup + +requires = [ + 'pyramid', + 'pyramid_chameleon', + 'deform', + 'sqlalchemy', + 'pyramid_tm', + 'zope.sqlalchemy' +] + +setup(name='poconsole', + install_requires=requires, + entry_points="""\ + [paste.app_factory] + main = poconsole:main + [console_scripts] + initialize_poconsole_db = poconsole.initialize_db:main + """, +) \ No newline at end of file