extended commit (see note)
- Slight overhaul of init() system; added ``edbob.init_modules()`` function. - Added ``read_service()`` method to ``AppConfigParser`` class, for use with Windows services. - Added generic ``Service`` class to ``edbob.win32`` module. (File monitor now inherits from it.) - Tweaked ``edbob.db`` initialization somewhat. (``Base.metadata`` no longer binds to ``edbob.db.engine``.) - Fixed guest role bug in ``edbob.db.auth.has_permission()`` function. - Added "automagical" enumeration support for database extensions. - Added ``EMAIL_PREFERENCE`` enum to ``contact`` database extension. - Tweaked ``edbob.pyramid.includeme()``. - Tweaked ``people`` Pyramid views.
This commit is contained in:
parent
526ff5dd6b
commit
c7e0bfef6a
18 changed files with 457 additions and 248 deletions
|
@ -34,6 +34,3 @@ from edbob.files import *
|
|||
from edbob.modules import *
|
||||
from edbob.configuration import *
|
||||
from edbob.initialization import *
|
||||
|
||||
|
||||
inited = False
|
||||
|
|
|
@ -289,6 +289,25 @@ class AppConfigParser(ConfigParser.SafeConfigParser):
|
|||
self.paths_loaded.append(path)
|
||||
log.info("Read config file: %s" % path)
|
||||
|
||||
def read_service(self, service, paths):
|
||||
"""
|
||||
"Special" version of :meth:`read()` which will first inspect the
|
||||
file(s) for a service-specific directive, the presence of which
|
||||
indicates the *true* config file to be used for the service.
|
||||
|
||||
This method is pretty much a hack to get around certain limitations of
|
||||
Windows service implementations; it is not used otherwise.
|
||||
"""
|
||||
|
||||
config = ConfigParser.SafeConfigParser()
|
||||
config.read(paths)
|
||||
|
||||
if (config.has_section('edbob.service_config')
|
||||
and config.has_option('edbob.service_config', service)):
|
||||
paths = eval(config.get('edbob.service_config', service))
|
||||
|
||||
self.read(paths, recurse=True)
|
||||
|
||||
def require(self, section, option, msg=None):
|
||||
"""
|
||||
Convenience method which will raise an exception if the given option
|
||||
|
|
|
@ -37,7 +37,6 @@ import edbob
|
|||
|
||||
__all__ = ['engines', 'engine', 'Session', 'get_setting', 'save_setting']
|
||||
|
||||
inited = False
|
||||
engines = None
|
||||
engine = None
|
||||
Session = sessionmaker()
|
||||
|
@ -71,36 +70,36 @@ def init(config):
|
|||
from edbob.db import enum
|
||||
from edbob.db.extensions import extend_framework
|
||||
|
||||
global inited, engines, engine
|
||||
global engines, engine
|
||||
|
||||
keys = config.get('edbob.db', 'sqlalchemy.keys')
|
||||
keys = config.get('edbob.db', 'keys')
|
||||
if keys:
|
||||
keys = keys.split()
|
||||
keys = keys.split(',')
|
||||
else:
|
||||
keys = ['default']
|
||||
|
||||
engines = {}
|
||||
cfg = config.get_dict('edbob.db')
|
||||
for key in keys:
|
||||
key = key.strip()
|
||||
try:
|
||||
engines[key] = engine_from_config(cfg, 'sqlalchemy.%s.' % key)
|
||||
engines[key] = engine_from_config(cfg, '%s.' % key)
|
||||
except KeyError:
|
||||
if key == 'default':
|
||||
try:
|
||||
engines[key] = engine_from_config(cfg)
|
||||
engines[key] = engine_from_config(cfg, 'sqlalchemy.')
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
engine = engines.get('default')
|
||||
if engine:
|
||||
Base.metadata.bind = engine
|
||||
Session.configure(bind=engine)
|
||||
|
||||
extend_framework()
|
||||
|
||||
edbob.graft(edbob, edbob.db)
|
||||
edbob.graft(edbob, model)
|
||||
edbob.graft(edbob, enum)
|
||||
inited = True
|
||||
|
||||
|
||||
def get_setting(name, session=None):
|
||||
|
|
|
@ -85,12 +85,12 @@ def guest_role(session):
|
|||
"""
|
||||
|
||||
uuid = 'f8a27c98965a11dfaff7001143047286'
|
||||
admin = session.query(edbob.Role).get(uuid)
|
||||
if admin:
|
||||
return admin
|
||||
admin = edbob.Role(uuid=uuid, name='Guest')
|
||||
session.add(admin)
|
||||
return admin
|
||||
guest = session.query(edbob.Role).get(uuid)
|
||||
if guest:
|
||||
return guest
|
||||
guest = edbob.Role(uuid=uuid, name='Guest')
|
||||
session.add(guest)
|
||||
return guest
|
||||
|
||||
|
||||
def grant_permission(role, permission, session=None):
|
||||
|
@ -114,7 +114,7 @@ def has_permission(obj, perm, session=None):
|
|||
"""
|
||||
|
||||
if isinstance(obj, edbob.User):
|
||||
roles = obj.roles
|
||||
roles = list(obj.roles)
|
||||
elif isinstance(obj, edbob.Role):
|
||||
roles = [obj]
|
||||
elif obj is None:
|
||||
|
|
|
@ -76,6 +76,11 @@ class Extension(edbob.Object):
|
|||
# :meth:`Extension.get_models_module()` for more info).
|
||||
model_module = ''
|
||||
|
||||
# You can set this to any dotted module path you like. If unset a default
|
||||
# will be assumed, of the form ``<path.to.extension>.enum`` (see
|
||||
# :meth:`Extension.get_enum_module()` for more info).
|
||||
enum_module = ''
|
||||
|
||||
# @property
|
||||
# @requires_impl(is_property=True)
|
||||
# def name(self):
|
||||
|
@ -119,6 +124,9 @@ class Extension(edbob.Object):
|
|||
"""
|
||||
|
||||
edbob.graft(edbob, self.get_model_module())
|
||||
enum = self.get_enum_module()
|
||||
if enum:
|
||||
edbob.graft(edbob, enum)
|
||||
|
||||
# def extend_mappers(self, metadata):
|
||||
# """
|
||||
|
@ -144,6 +152,26 @@ class Extension(edbob.Object):
|
|||
self.populate_metadata(meta, recurse)
|
||||
return meta
|
||||
|
||||
def get_enum_module(self):
|
||||
"""
|
||||
Imports and returns a reference to the Python module providing
|
||||
enumeration data for the extension (if one exists).
|
||||
|
||||
:attr:`Extension.enum_module` is first consulted to determine the
|
||||
dotted module path. If nothing is found there, a default path is
|
||||
constructed by appending ``'.enum'`` to the extension module's own
|
||||
dotted path.
|
||||
"""
|
||||
|
||||
if self.enum_module:
|
||||
module = self.enum_module
|
||||
else:
|
||||
module = str(self.__class__.__module__) + '.enum'
|
||||
try:
|
||||
return import_module_path(module)
|
||||
except ImportError:
|
||||
return None
|
||||
|
||||
def get_model_module(self):
|
||||
"""
|
||||
Imports and returns a reference to the Python module providing schema
|
||||
|
|
40
edbob/db/extensions/contact/enum.py
Normal file
40
edbob/db/extensions/contact/enum.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
################################################################################
|
||||
#
|
||||
# edbob -- Pythonic Software Framework
|
||||
# Copyright © 2010-2012 Lance Edgar
|
||||
#
|
||||
# This file is part of edbob.
|
||||
#
|
||||
# edbob is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# edbob is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with edbob. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
"""
|
||||
``edbob.db.extensions.contact.enum`` -- Enumerations
|
||||
"""
|
||||
|
||||
|
||||
EMAIL_PREFERENCE_NONE = 0
|
||||
EMAIL_PREFERENCE_TEXT = 1
|
||||
EMAIL_PREFERENCE_HTML = 2
|
||||
EMAIL_PREFERENCE_MOBILE = 3
|
||||
|
||||
EMAIL_PREFERENCE = {
|
||||
EMAIL_PREFERENCE_NONE : "No Emails",
|
||||
EMAIL_PREFERENCE_TEXT : "Text",
|
||||
EMAIL_PREFERENCE_HTML : "HTML",
|
||||
EMAIL_PREFERENCE_MOBILE : "Mobile",
|
||||
}
|
|
@ -35,7 +35,7 @@ import threading
|
|||
import edbob
|
||||
from edbob.errors import email_exception
|
||||
from edbob.filemon import get_monitor_profiles
|
||||
from edbob.win32 import file_is_free
|
||||
from edbob.win32 import Service, file_is_free
|
||||
|
||||
if sys.platform == 'win32': # docs should build for everyone
|
||||
import win32api
|
||||
|
@ -50,36 +50,23 @@ if sys.platform == 'win32': # docs should build for everyone
|
|||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FileMonitorService(win32serviceutil.ServiceFramework):
|
||||
class FileMonitorService(Service):
|
||||
"""
|
||||
Implements edbob's file monitor Windows service.
|
||||
"""
|
||||
|
||||
_svc_name_ = "Edbob File Monitor"
|
||||
_svc_name_ = 'EdbobFileMonitor'
|
||||
_svc_display_name_ = "Edbob : File Monitoring Service"
|
||||
_svc_description_ = ("Monitors one or more folders for incoming files, "
|
||||
"and performs configured actions as new files arrive.")
|
||||
|
||||
appname = 'edbob'
|
||||
|
||||
def __init__(self, args):
|
||||
"""
|
||||
Constructor.
|
||||
"""
|
||||
|
||||
# super(FileMonitorService, self).__init__(args)
|
||||
win32serviceutil.ServiceFramework.__init__(self, args)
|
||||
|
||||
# Create "wait stop" event, for main worker loop.
|
||||
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
|
||||
|
||||
def Initialize(self):
|
||||
"""
|
||||
Service initialization.
|
||||
"""
|
||||
|
||||
# Read configuration file(s).
|
||||
edbob.init(self.appname)
|
||||
if not Service.Initialize(self):
|
||||
return False
|
||||
|
||||
# Read monitor profile(s) from config.
|
||||
self.monitored = get_monitor_profiles(self.appname)
|
||||
|
@ -118,50 +105,6 @@ class FileMonitorService(win32serviceutil.ServiceFramework):
|
|||
|
||||
return True
|
||||
|
||||
def SvcDoRun(self):
|
||||
"""
|
||||
This method is invoked when the service starts.
|
||||
"""
|
||||
|
||||
import servicemanager
|
||||
|
||||
# Write start occurrence to Windows Event Log.
|
||||
servicemanager.LogMsg(
|
||||
servicemanager.EVENTLOG_INFORMATION_TYPE,
|
||||
servicemanager.PYS_SERVICE_STARTED,
|
||||
(self._svc_name_, ''))
|
||||
|
||||
# Figure out what we're supposed to be doing.
|
||||
if self.Initialize():
|
||||
|
||||
# Wait infinitely for stop request, while threads do their thing.
|
||||
log.info("SvcDoRun: All threads started; waiting for stop request.")
|
||||
win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
|
||||
log.info("SvcDoRun: Stop request received.")
|
||||
|
||||
else: # Nothing to be done...
|
||||
msg = "Nothing to do! No valid monitor profiles found in config."
|
||||
servicemanager.LogWarningMsg(msg)
|
||||
log.warning("SvcDoRun: %s" % msg)
|
||||
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
|
||||
|
||||
# Write stop occurrence to Windows Event Log.
|
||||
servicemanager.LogMsg(
|
||||
servicemanager.EVENTLOG_INFORMATION_TYPE,
|
||||
servicemanager.PYS_SERVICE_STOPPED,
|
||||
(self._svc_name_, ''))
|
||||
|
||||
def SvcStop(self):
|
||||
"""
|
||||
This method is invoked when the service is requested to stop itself.
|
||||
"""
|
||||
|
||||
# Let the SCM know we're trying to stop.
|
||||
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
|
||||
|
||||
# Let worker loop know its job is done.
|
||||
win32event.SetEvent(self.hWaitStop)
|
||||
|
||||
|
||||
def monitor_files(queue, path, profile):
|
||||
"""
|
||||
|
|
|
@ -38,7 +38,9 @@ from edbob.configuration import (
|
|||
from edbob.exceptions import InitError
|
||||
|
||||
|
||||
__all__ = ['init']
|
||||
__all__ = ['init', 'init_modules', 'inited']
|
||||
|
||||
inited = []
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -80,7 +82,11 @@ def init(appname='edbob', *args, **kwargs):
|
|||
else:
|
||||
config_paths = default_system_paths(appname) + default_user_paths(appname)
|
||||
|
||||
shell = bool(kwargs.get('shell'))
|
||||
service = kwargs.get('service')
|
||||
if service:
|
||||
config.read_service(service, config_paths)
|
||||
else:
|
||||
shell = kwargs.get('shell', False)
|
||||
for paths in config_paths:
|
||||
config.read(paths, recurse=not shell)
|
||||
config.configure_logging()
|
||||
|
@ -88,14 +94,28 @@ def init(appname='edbob', *args, **kwargs):
|
|||
default_modules = 'edbob.time'
|
||||
modules = config.get('edbob', 'init', default=default_modules)
|
||||
if modules:
|
||||
for name in modules.split(','):
|
||||
modules = modules.split(',')
|
||||
init_modules(modules, config)
|
||||
|
||||
edbob.graft(edbob, locals(), 'config')
|
||||
inited.append('edbob')
|
||||
|
||||
|
||||
def init_modules(names, config=None):
|
||||
"""
|
||||
Initialize the given modules. ``names`` should be a sequence of strings,
|
||||
each of which should be a dotted module name. If ``config`` is not
|
||||
specified, :attr:`edbob.config` is assumed.
|
||||
"""
|
||||
|
||||
if config is None:
|
||||
config = edbob.config
|
||||
|
||||
for name in names:
|
||||
name = name.strip()
|
||||
if name not in inited:
|
||||
module = __import__(name, globals(), locals(), fromlist=['init'])
|
||||
if not hasattr(module, 'init'):
|
||||
raise InitError(module)
|
||||
getattr(module, 'init')(config)
|
||||
# config.inited.append(name)
|
||||
|
||||
# config.inited.append('edbob')
|
||||
edbob.graft(edbob, locals(), 'config')
|
||||
edbob.inited = True
|
||||
inited.append(name)
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
from zope.sqlalchemy import ZopeTransactionExtension
|
||||
|
||||
import edbob
|
||||
|
||||
|
||||
__all__ = ['Session']
|
||||
|
||||
|
@ -56,6 +58,7 @@ def includeme(config):
|
|||
config.include('pyramid_tm')
|
||||
|
||||
# Configure SQLAlchemy session.
|
||||
Session.configure(bind=edbob.engine)
|
||||
Session.configure(extension=ZopeTransactionExtension())
|
||||
|
||||
# Configure user authentication / authorization.
|
||||
|
@ -69,3 +72,6 @@ def includeme(config):
|
|||
|
||||
# Add static views.
|
||||
config.include('edbob.pyramid.static')
|
||||
|
||||
# Add subscriber hooks.
|
||||
config.include('edbob.pyramid.subscribers')
|
||||
|
|
|
@ -74,12 +74,10 @@ def EnumFieldRenderer(enum):
|
|||
return ''
|
||||
if value in enum:
|
||||
return enum[value]
|
||||
return value
|
||||
return str(value)
|
||||
|
||||
def render(self, **kwargs):
|
||||
opts = []
|
||||
for value in sorted(enum):
|
||||
opts.append((enum[value], value))
|
||||
opts = [(enum[x], x) for x in sorted(enum)]
|
||||
return formalchemy.fields.SelectFieldRenderer.render(self, opts, **kwargs)
|
||||
|
||||
return Renderer
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<%inherit file="/form.mako" />
|
||||
|
||||
<%def name="title()">${"New "+form.pretty_name if form.creating else form.pretty_name+' : '+str(form.fieldset.model)}</%def>
|
||||
<%def name="title()">${"New "+form.pretty_name if form.creating else form.pretty_name+' : '+h.literal(str(form.fieldset.model))}</%def>
|
||||
|
||||
${parent.body()}
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
<%inherit file="/base.mako" />
|
||||
${parent.body()}
|
28
edbob/pyramid/templates/people/crud.mako
Normal file
28
edbob/pyramid/templates/people/crud.mako
Normal file
|
@ -0,0 +1,28 @@
|
|||
<%inherit file="/crud.mako" />
|
||||
|
||||
<%def name="crud_name()">Person</%def>
|
||||
|
||||
<%def name="context_menu_items()">
|
||||
<li>${h.link_to("Back to People", url('people'))}</li>
|
||||
</%def>
|
||||
|
||||
${parent.body()}
|
||||
|
||||
## % if fieldset.edit:
|
||||
## <h2>User Info</h2>
|
||||
## % if user:
|
||||
## ${user.render()|n}
|
||||
## <div class="buttons">
|
||||
## <button type="button" onclick="location.href = '${url('user.edit', uuid=user.model.uuid)}';">Edit User</button>
|
||||
## </div>
|
||||
## % else:
|
||||
## <p>This person does not have a user account.</p>
|
||||
## ${h.form(url('user.new'))}
|
||||
## ${h.hidden('User--person_uuid', value=fieldset.model.uuid)}
|
||||
## ${h.hidden('User--username')}
|
||||
## <div class="buttons">
|
||||
## ${h.submit('submit', "Create User")}
|
||||
## </div>
|
||||
## ${h.end_form()}
|
||||
## % endif
|
||||
## % endif
|
|
@ -1,12 +1,11 @@
|
|||
<%inherit file="/people/base.mako" />
|
||||
<%inherit file="/index.mako" />
|
||||
<%inherit file="/grid.mako" />
|
||||
|
||||
<%def name="title()">People</%def>
|
||||
|
||||
<%def name="context_menu_items()">
|
||||
% if request.has_perm('people.create'):
|
||||
<li>${h.link_to("Create a new Person", url('person.new'))}</li>
|
||||
% endif
|
||||
## % if request.has_perm('people.create'):
|
||||
## <li>${h.link_to("Create a new Person", url('person.new'))}</li>
|
||||
## % endif
|
||||
</%def>
|
||||
|
||||
${parent.body()}
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
<%inherit file="/people/base.mako" />
|
||||
<%inherit file="/crud.mako" />
|
||||
|
||||
<%def name="crud_name()">Person</%def>
|
||||
|
||||
<%def name="menu()">
|
||||
<p>${h.link_to("Back to People", url('people.list'))}</p>
|
||||
</%def>
|
||||
|
||||
${parent.body()}
|
||||
|
||||
% if fieldset.edit:
|
||||
<h2>User Info</h2>
|
||||
% if user:
|
||||
${user.render()|n}
|
||||
<div class="buttons">
|
||||
<button type="button" onclick="location.href = '${url('user.edit', uuid=user.model.uuid)}';">Edit User</button>
|
||||
</div>
|
||||
% else:
|
||||
<p>This person does not have a user account.</p>
|
||||
${h.form(url('user.new'))}
|
||||
${h.hidden('User--person_uuid', value=fieldset.model.uuid)}
|
||||
${h.hidden('User--username')}
|
||||
<div class="buttons">
|
||||
${h.submit('submit', "Create User")}
|
||||
</div>
|
||||
${h.end_form()}
|
||||
% endif
|
||||
% endif
|
|
@ -26,155 +26,239 @@
|
|||
``edbob.pyramid.views.people`` -- Person Views
|
||||
"""
|
||||
|
||||
import transaction
|
||||
from pyramid.httpexceptions import HTTPFound
|
||||
from sqlalchemy import and_
|
||||
|
||||
from formalchemy import Field
|
||||
# import transaction
|
||||
# from pyramid.httpexceptions import HTTPFound
|
||||
|
||||
# from formalchemy import Field
|
||||
|
||||
import edbob
|
||||
from edbob.pyramid import filters
|
||||
from edbob.pyramid import forms
|
||||
from edbob.pyramid import grids
|
||||
from edbob.pyramid import Session
|
||||
# from edbob.pyramid import filters
|
||||
# from edbob.pyramid import forms
|
||||
# from edbob.pyramid import grids
|
||||
# from edbob.pyramid import Session
|
||||
from edbob.pyramid.views import SearchableAlchemyGridView, CrudView
|
||||
|
||||
|
||||
def filter_map():
|
||||
return filters.get_filter_map(
|
||||
edbob.Person,
|
||||
ilike=['first_name', 'last_name', 'display_name'])
|
||||
class PeopleGrid(SearchableAlchemyGridView):
|
||||
|
||||
def search_config(request, fmap):
|
||||
return filters.get_search_config(
|
||||
'people.list', request, fmap,
|
||||
include_filter_display_name=True,
|
||||
filter_type_display_name='lk')
|
||||
mapped_class = edbob.Person
|
||||
config_prefix = 'people'
|
||||
sort = 'first_name'
|
||||
|
||||
def search_form(config):
|
||||
return filters.get_search_form(config)
|
||||
def join_map(self):
|
||||
return {
|
||||
'email':
|
||||
lambda q: q.outerjoin(edbob.PersonEmailAddress, and_(
|
||||
edbob.PersonEmailAddress.parent_uuid == edbob.Person.uuid,
|
||||
edbob.PersonEmailAddress.preference == 1)),
|
||||
'phone':
|
||||
lambda q: q.outerjoin(edbob.PersonPhoneNumber, and_(
|
||||
edbob.PersonPhoneNumber.parent_uuid == edbob.Person.uuid,
|
||||
edbob.PersonPhoneNumber.preference == 1)),
|
||||
}
|
||||
|
||||
def grid_config(request, search, fmap):
|
||||
return grids.get_grid_config(
|
||||
'people.list', request, search,
|
||||
filter_map=fmap, sort='display_name')
|
||||
def filter_map(self):
|
||||
return self.make_filter_map(
|
||||
ilike=['first_name', 'last_name'],
|
||||
email=self.filter_ilike(edbob.PersonEmailAddress.address),
|
||||
phone=self.filter_ilike(edbob.PersonPhoneNumber.number))
|
||||
|
||||
def sort_map():
|
||||
return grids.get_sort_map(
|
||||
edbob.Person,
|
||||
['first_name', 'last_name', 'display_name'])
|
||||
def filter_config(self):
|
||||
return self.make_filter_config(
|
||||
include_filter_first_name=True,
|
||||
filter_type_first_name='lk',
|
||||
include_filter_last_name=True,
|
||||
filter_type_last_name='lk',
|
||||
filter_label_phone="Phone Number",
|
||||
filter_label_email="Email Address")
|
||||
|
||||
def query(config):
|
||||
smap = sort_map()
|
||||
q = Session.query(edbob.Person)
|
||||
q = filters.filter_query(q, config)
|
||||
q = grids.sort_query(q, config, smap)
|
||||
return q
|
||||
|
||||
|
||||
def people(context, request):
|
||||
|
||||
fmap = filter_map()
|
||||
config = search_config(request, fmap)
|
||||
search = search_form(config)
|
||||
config = grid_config(request, search, fmap)
|
||||
people = grids.get_pager(query, config)
|
||||
|
||||
g = forms.AlchemyGrid(
|
||||
edbob.Person, people, config,
|
||||
gridurl=request.route_url('people.list'),
|
||||
objurl='person.edit')
|
||||
def sort_map(self):
|
||||
return self.make_sort_map(
|
||||
'first_name', 'last_name',
|
||||
email=self.sorter(edbob.PersonEmailAddress.address),
|
||||
phone=self.sorter(edbob.PersonPhoneNumber.number))
|
||||
|
||||
def grid(self):
|
||||
g = self.make_grid()
|
||||
g.configure(
|
||||
include=[
|
||||
g.first_name,
|
||||
g.last_name,
|
||||
g.display_name,
|
||||
g.phone.label("Phone Number"),
|
||||
g.email.label("Email Address"),
|
||||
],
|
||||
readonly=True)
|
||||
|
||||
grid = g.render(class_='clickable people')
|
||||
return grids.render_grid(request, grid, search)
|
||||
g.clickable = True
|
||||
g.click_route_name = 'person.read'
|
||||
return g
|
||||
|
||||
|
||||
def person_fieldset(person, request):
|
||||
fs = forms.make_fieldset(person, url=request.route_url,
|
||||
url_action=request.current_route_url(),
|
||||
route_name='people.list')
|
||||
class PersonCrud(CrudView):
|
||||
|
||||
mapped_class = edbob.Person
|
||||
home_route = 'people'
|
||||
|
||||
def fieldset(self, model):
|
||||
fs = self.make_fieldset(model)
|
||||
fs.configure(
|
||||
include=[
|
||||
fs.first_name,
|
||||
fs.last_name,
|
||||
fs.display_name,
|
||||
fs.phone.label("Phone Number"),
|
||||
fs.email.label("Email Address"),
|
||||
])
|
||||
return fs
|
||||
|
||||
|
||||
def new_person(context, request):
|
||||
# def filter_map():
|
||||
# return filters.get_filter_map(
|
||||
# edbob.Person,
|
||||
# ilike=['first_name', 'last_name', 'display_name'])
|
||||
|
||||
fs = person_fieldset(edbob.Person, request)
|
||||
if not fs.readonly and request.POST:
|
||||
fs.rebind(data=request.params)
|
||||
if fs.validate():
|
||||
# def search_config(request, fmap):
|
||||
# return filters.get_search_config(
|
||||
# 'people.list', request, fmap,
|
||||
# include_filter_display_name=True,
|
||||
# filter_type_display_name='lk')
|
||||
|
||||
with transaction.manager:
|
||||
fs.sync()
|
||||
Session.add(fs.model)
|
||||
Session.flush()
|
||||
request.session.flash("%s \"%s\" has been %s." % (
|
||||
fs.crud_title, fs.get_display_text(),
|
||||
'updated' if fs.edit else 'created'))
|
||||
# def search_form(config):
|
||||
# return filters.get_search_form(config)
|
||||
|
||||
return HTTPFound(location=request.route_url('people.list'))
|
||||
# def grid_config(request, search, fmap):
|
||||
# return grids.get_grid_config(
|
||||
# 'people.list', request, search,
|
||||
# filter_map=fmap, sort='display_name')
|
||||
|
||||
return {'fieldset': fs, 'crud': True}
|
||||
# def sort_map():
|
||||
# return grids.get_sort_map(
|
||||
# edbob.Person,
|
||||
# ['first_name', 'last_name', 'display_name'])
|
||||
|
||||
# def query(config):
|
||||
# smap = sort_map()
|
||||
# q = Session.query(edbob.Person)
|
||||
# q = filters.filter_query(q, config)
|
||||
# q = grids.sort_query(q, config, smap)
|
||||
# return q
|
||||
|
||||
|
||||
def edit_person(request):
|
||||
"""
|
||||
View for editing a :class:`edbob.Person` instance.
|
||||
"""
|
||||
# def people(context, request):
|
||||
|
||||
from edbob.pyramid.views.users import user_fieldset
|
||||
# fmap = filter_map()
|
||||
# config = search_config(request, fmap)
|
||||
# search = search_form(config)
|
||||
# config = grid_config(request, search, fmap)
|
||||
# people = grids.get_pager(query, config)
|
||||
|
||||
uuid = request.matchdict['uuid']
|
||||
person = Session.query(edbob.Person).get(uuid) if uuid else None
|
||||
assert person
|
||||
# g = forms.AlchemyGrid(
|
||||
# edbob.Person, people, config,
|
||||
# gridurl=request.route_url('people.list'),
|
||||
# objurl='person.edit')
|
||||
|
||||
fs = person_fieldset(person, request)
|
||||
if request.POST:
|
||||
fs.rebind(data=request.params)
|
||||
if fs.validate():
|
||||
# g.configure(
|
||||
# include=[
|
||||
# g.first_name,
|
||||
# g.last_name,
|
||||
# g.display_name,
|
||||
# ],
|
||||
# readonly=True)
|
||||
|
||||
with transaction.manager:
|
||||
fs.sync()
|
||||
fs.model = Session.merge(fs.model)
|
||||
request.session.flash("%s \"%s\" has been %s." % (
|
||||
fs.crud_title, fs.get_display_text(),
|
||||
'updated' if fs.edit else 'created'))
|
||||
home = request.route_url('people.list')
|
||||
# grid = g.render(class_='clickable people')
|
||||
# return grids.render_grid(request, grid, search)
|
||||
|
||||
return HTTPFound(location=home)
|
||||
|
||||
user = fs.model.user
|
||||
if user:
|
||||
user = user_fieldset(user, request)
|
||||
user.readonly = True
|
||||
del user.person
|
||||
del user.password
|
||||
del user.confirm_password
|
||||
# def person_fieldset(person, request):
|
||||
# fs = forms.make_fieldset(person, url=request.route_url,
|
||||
# url_action=request.current_route_url(),
|
||||
# route_name='people.list')
|
||||
# fs.configure(
|
||||
# include=[
|
||||
# fs.first_name,
|
||||
# fs.last_name,
|
||||
# fs.display_name,
|
||||
# ])
|
||||
# return fs
|
||||
|
||||
return {'fieldset': fs, 'crud': True, 'user': user}
|
||||
|
||||
# def new_person(context, request):
|
||||
|
||||
# fs = person_fieldset(edbob.Person, request)
|
||||
# if not fs.readonly and request.POST:
|
||||
# fs.rebind(data=request.params)
|
||||
# if fs.validate():
|
||||
|
||||
# with transaction.manager:
|
||||
# fs.sync()
|
||||
# Session.add(fs.model)
|
||||
# Session.flush()
|
||||
# request.session.flash("%s \"%s\" has been %s." % (
|
||||
# fs.crud_title, fs.get_display_text(),
|
||||
# 'updated' if fs.edit else 'created'))
|
||||
|
||||
# return HTTPFound(location=request.route_url('people.list'))
|
||||
|
||||
# return {'fieldset': fs, 'crud': True}
|
||||
|
||||
|
||||
# def edit_person(request):
|
||||
# """
|
||||
# View for editing a :class:`edbob.Person` instance.
|
||||
# """
|
||||
|
||||
# from edbob.pyramid.views.users import user_fieldset
|
||||
|
||||
# uuid = request.matchdict['uuid']
|
||||
# person = Session.query(edbob.Person).get(uuid) if uuid else None
|
||||
# assert person
|
||||
|
||||
# fs = person_fieldset(person, request)
|
||||
# if request.POST:
|
||||
# fs.rebind(data=request.params)
|
||||
# if fs.validate():
|
||||
|
||||
# with transaction.manager:
|
||||
# fs.sync()
|
||||
# fs.model = Session.merge(fs.model)
|
||||
# request.session.flash("%s \"%s\" has been %s." % (
|
||||
# fs.crud_title, fs.get_display_text(),
|
||||
# 'updated' if fs.edit else 'created'))
|
||||
# home = request.route_url('people.list')
|
||||
|
||||
# return HTTPFound(location=home)
|
||||
|
||||
# user = fs.model.user
|
||||
# if user:
|
||||
# user = user_fieldset(user, request)
|
||||
# user.readonly = True
|
||||
# del user.person
|
||||
# del user.password
|
||||
# del user.confirm_password
|
||||
|
||||
# return {'fieldset': fs, 'crud': True, 'user': user}
|
||||
|
||||
|
||||
def includeme(config):
|
||||
|
||||
config.add_route('people.list', '/people')
|
||||
config.add_view(people, route_name='people.list', renderer='/people/index.mako',
|
||||
permission='people.list', http_cache=0)
|
||||
config.add_route('people', '/people')
|
||||
config.add_view(PeopleGrid, route_name='people',
|
||||
renderer='/people/index.mako',
|
||||
permission='people.list')
|
||||
|
||||
config.add_route('person.new', '/people/new')
|
||||
config.add_view(new_person, route_name='person.new', renderer='/people/person.mako',
|
||||
permission='people.create', http_cache=0)
|
||||
# config.add_route('people.list', '/people')
|
||||
# config.add_view(people, route_name='people.list', renderer='/people/index.mako',
|
||||
# permission='people.list', http_cache=0)
|
||||
|
||||
config.add_route('person.edit', '/people/{uuid}/edit')
|
||||
config.add_view(edit_person, route_name='person.edit', renderer='/people/person.mako',
|
||||
permission='people.edit', http_cache=0)
|
||||
config.add_route('person.read', '/people/{uuid}')
|
||||
config.add_view(PersonCrud, attr='read', route_name='person.read',
|
||||
renderer='/people/crud.mako',
|
||||
permission='people.read')
|
||||
|
||||
# config.add_route('person.new', '/people/new')
|
||||
# config.add_view(new_person, route_name='person.new', renderer='/people/person.mako',
|
||||
# permission='people.create', http_cache=0)
|
||||
|
||||
# config.add_route('person.edit', '/people/{uuid}/edit')
|
||||
# config.add_view(edit_person, route_name='person.edit', renderer='/people/person.mako',
|
||||
# permission='people.edit', http_cache=0)
|
||||
|
|
|
@ -69,7 +69,6 @@ setup(
|
|||
],
|
||||
|
||||
install_requires = requires,
|
||||
tests_require = requires,
|
||||
|
||||
packages = find_packages(),
|
||||
include_package_data = True,
|
||||
|
|
|
@ -28,16 +28,96 @@
|
|||
|
||||
import sys
|
||||
import subprocess
|
||||
import logging
|
||||
|
||||
if sys.platform == 'win32': # docs should build for everyone
|
||||
import pywintypes
|
||||
import win32api
|
||||
import win32con
|
||||
import win32event
|
||||
import win32file
|
||||
import win32print
|
||||
import win32service
|
||||
import win32serviceutil
|
||||
import winerror
|
||||
|
||||
import edbob
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Service(win32serviceutil.ServiceFramework):
|
||||
"""
|
||||
Base class for Windows service implementations.
|
||||
"""
|
||||
|
||||
appname = 'edbob'
|
||||
|
||||
def __init__(self, args):
|
||||
"""
|
||||
Constructor.
|
||||
"""
|
||||
|
||||
win32serviceutil.ServiceFramework.__init__(self, args)
|
||||
|
||||
# Create "wait stop" event, for main worker loop.
|
||||
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
|
||||
|
||||
def Initialize(self):
|
||||
"""
|
||||
Service initialization.
|
||||
"""
|
||||
|
||||
# Read configuration file(s).
|
||||
edbob.init(self.appname, service=self._svc_name_)
|
||||
|
||||
return True
|
||||
|
||||
def SvcDoRun(self):
|
||||
"""
|
||||
This method is invoked when the service starts.
|
||||
"""
|
||||
|
||||
import servicemanager
|
||||
|
||||
# Write start occurrence to Windows Event Log.
|
||||
servicemanager.LogMsg(
|
||||
servicemanager.EVENTLOG_INFORMATION_TYPE,
|
||||
servicemanager.PYS_SERVICE_STARTED,
|
||||
(self._svc_name_, ''))
|
||||
|
||||
# Figure out what we're supposed to be doing.
|
||||
if self.Initialize():
|
||||
|
||||
# Wait infinitely for stop request, while threads do their thing.
|
||||
log.info("SvcDoRun: All threads started; waiting for stop request.")
|
||||
win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
|
||||
log.info("SvcDoRun: Stop request received.")
|
||||
|
||||
else: # Nothing to be done...
|
||||
msg = "Nothing to do! (Initialization failed.)"
|
||||
servicemanager.LogWarningMsg(msg)
|
||||
log.warning("SvcDoRun: %s" % msg)
|
||||
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
|
||||
|
||||
# Write stop occurrence to Windows Event Log.
|
||||
servicemanager.LogMsg(
|
||||
servicemanager.EVENTLOG_INFORMATION_TYPE,
|
||||
servicemanager.PYS_SERVICE_STOPPED,
|
||||
(self._svc_name_, ''))
|
||||
|
||||
def SvcStop(self):
|
||||
"""
|
||||
This method is invoked when the service is requested to stop itself.
|
||||
"""
|
||||
|
||||
# Let the SCM know we're trying to stop.
|
||||
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
|
||||
|
||||
# Let worker loop know its job is done.
|
||||
win32event.SetEvent(self.hWaitStop)
|
||||
|
||||
|
||||
def RegDeleteTree(key, subkey):
|
||||
"""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue