class SimpleDemo(SectionPlugin): def init(self): self.title = "Binder" self.icon = "question" self.category = "Demo" self.append(self.ui.inflate("test:binder-main")) self.data = [Person("Alice", "123"), Person("Bob", "234")] self.dict = {"a": 1, "b": 2} self.find("data").text = repr(self.data) self.binder = Binder(self, self.find("bindroot")) @on("populate", "click") def on_populate(self): self.binder.populate() @on("unpopulate", "click") def on_unpopulate(self): self.binder.unpopulate() @on("update", "click") def on_update(self): self.binder.update() self.find("data").text = repr(self.data)
class SimpleDemo (SectionPlugin): def init(self): self.title = 'Binder' self.icon = 'question' self.category = 'Demo' self.append(self.ui.inflate('test:binder-main')) self.data = [ Person('Alice', '123'), Person('Bob', '234'), ] self.find('data').text = repr(self.data) self.binder = Binder(self, self.find('bindroot')) @on('populate', 'click') def on_populate(self): self.binder.populate() @on('unpopulate', 'click') def on_unpopulate(self): self.binder.unpopulate() @on('update', 'click') def on_update(self): self.binder.update() self.find('data').text = repr(self.data)
class Filesystems (SectionPlugin): def init(self): self.title = _('Filesystems') self.icon = 'hdd' self.category = _('System') self.append(self.ui.inflate('fstab:main')) self.find('type').labels = ['Auto', 'EXT2', 'EXT3', 'EXT4', 'NTFS', 'FAT', 'ZFS', 'ReiserFS', 'Samba', 'None', 'Loop'] self.find('type').values = ['auto', 'ext2', 'ext3', 'ext4', 'ntfs', 'vfat', 'zfs', 'reiser', 'smb', 'none', 'loop'] self.fstab_config = FSTabConfig(path='/etc/fstab') self.mounts = MountsBackend.get() self.binder = Binder(None, self) self.find('fstab').find('filesystems').new_item = lambda c: FilesystemData() def post_mount_bind(object, collection, item, ui): ui.find('umount').on('click', self.on_umount, item) self.find('mounts').find('filesystems').post_item_bind = post_mount_bind def on_page_load(self): self.refresh() def on_umount(self, mount): subprocess.call(['umount', mount.mountpoint]) self.context.notify('info', _('Unmounted')) self.refresh() @on('mount-all', 'click') def on_mount_all(self): self.save() if subprocess.call(['mount', '-a']): self.context.notify('error', _('mount -a failed')) self.refresh() @on('refresh', 'click') def refresh(self): self.binder.unpopulate() self.reload_disks() self.fstab_config.load() self.fstab = self.fstab_config.tree self.mounts.reload() self.binder.setup(self).populate() def reload_disks(self): lst = disks.list_devices(by_uuid=True, by_id=True, by_label=True) self.find('device').labels = [x[0] for x in lst] self.find('device').values = [x[1] for x in lst] @on('save', 'click') def save(self): self.binder.update() self.fstab_config.save() self.context.notify('info', _('Saved'))
class DBPlugin(SectionPlugin): service_name = '' service_buttons = [] has_users = True def init(self): self.append(self.ui.inflate('db_common:main')) self.binder = Binder(None, self) self.find_type('servicebar').buttons = self.service_buttons def delete_db(db, c): self.query_drop(db) self.refresh() self.find('databases').delete_item = delete_db def delete_user(user, c): self.query_drop_user(user) self.refresh() self.find('users').delete_item = delete_user def on_page_load(self): self.refresh() @on('sql-run', 'click') def on_sql_run(self): try: result = self.query_sql( self.find('sql-db').value, self.find('sql-input').value) self.context.notify('info', _('Query finished')) except Exception as e: self.context.notify('error', str(e)) return tbl = self.find('sql-output') tbl.empty() if len(result) > 200: self.context.notify( 'info', _('Output cut from %i rows to 200') % len(result)) result = result[:200] for row in result: erow = self.ui.create('dtr') tbl.append(erow) for cell in row: ecell = self.ui.create('dtd') ecell.append(self.ui.create('label', text=str(cell))) erow.append(ecell) @on('add-db', 'click') def on_add_db(self): self.find('db-name-dialog').value = '' self.find('db-name-dialog').visible = True @on('add-user', 'click') def on_add_user(self): self.find('add-user-dialog').visible = True def refresh(self): self.binder.setup(self).populate() self.databases = [] self.users = [] try: self.databases = self.query_databases() if self.has_users: self.users = self.query_users() except Exception as e: import traceback traceback.print_exc() self.context.notify('error', str(e)) if hasattr(self, 'config_class'): self.context.launch('configure-plugin', plugin=self.config_class.get()) return self.binder.unpopulate() self.find('sql-db').labels = self.find('sql-db').values = [ x.name for x in self.databases ] self.binder.populate() self.find_type('servicebar').reload() @on('db-name-dialog', 'submit') def on_db_name_dialog_submit(self, value=None): try: self.query_create(value) except Exception as e: self.context.notify('error', str(e)) return self.refresh() @on('add-user-dialog', 'button') def on_add_user_dialog(self, button=None): d = self.find('add-user-dialog') d.visible = False if button == 'ok': u = User() u.name = d.find('name').value u.host = d.find('host').value u.password = d.find('password').value try: self.query_create_user(u) except Exception as e: self.context.notify('error', str(e)) return self.refresh() def query_sql(self, db, sql): raise NotImplementedError() def query_databases(self): raise NotImplementedError() def query_drop(self, db): raise NotImplementedError() def query_create(self, name): raise NotImplementedError() def query_users(self): raise NotImplementedError() def query_create_user(self, user): raise NotImplementedError() def query_drop_user(self, user): raise NotImplementedError()
class Filesystems(SectionPlugin): def init(self): self.title = _("Filesystems") self.icon = "hdd" self.category = _("System") self.append(self.ui.inflate("fstab:main")) self.find("type").labels = [ "Auto", "EXT2", "EXT3", "EXT4", "NTFS", "FAT", "ZFS", "ReiserFS", "Samba", "None", "Loop", ] self.find("type").values = [ "auto", "ext2", "ext3", "ext4", "ntfs", "vfat", "zfs", "reiser", "smb", "none", "loop", ] self.fstab_config = FSTabConfig(path="/etc/fstab") self.mounts = MountsBackend.get() self.binder = Binder(None, self) self.find("fstab").find("filesystems").new_item = lambda c: FilesystemData() def post_mount_bind(object, collection, item, ui): ui.find("umount").on("click", self.on_umount, item) self.find("mounts").find("filesystems").post_item_bind = post_mount_bind def on_page_load(self): self.refresh() def on_umount(self, mount): subprocess.call(["umount", mount.mountpoint]) self.context.notify("info", _("Unmounted")) self.refresh() @on("mount-all", "click") def on_mount_all(self): self.save() if subprocess.call(["mount", "-a"]): self.context.notify("error", _("mount -a failed")) self.refresh() @on("refresh", "click") def refresh(self): self.binder.unpopulate() self.reload_disks() self.fstab_config.load() self.fstab = self.fstab_config.tree self.mounts.reload() self.binder.setup(self).populate() def reload_disks(self): lst = disks.list_devices(by_uuid=True, by_id=True, by_label=True) self.find("device").labels = [x[0] for x in lst] self.find("device").values = [x[1] for x in lst] @on("save", "click") def save(self): self.binder.update() self.fstab_config.save() self.context.notify("info", _("Saved"))
class MailPlugin (SectionPlugin): def init(self): self.title = _('Mail') self.icon = 'envelope' self.category = 'Web' self.manager = MailManager.get() if not self.manager.is_configured: self.append(self.ui.inflate('vh-mail:not-configured')) else: self.post_init() @on('initial-enable', 'click') def on_initial_enable(self): self.post_init() self.manager.save() self.refresh() def post_init(self): self.empty() self.append(self.ui.inflate('vh-mail:main')) self.binder = Binder(None, self) def post_mb_bind(object, collection, item, ui): ui.find('size').text = str_fsize(self.manager.get_usage(item)) def post_mb_update(object, collection, item, ui): if ui.find('password').value: item.password = ui.find('password').value self.find('mailboxes').post_item_bind = post_mb_bind self.find('mailboxes').post_item_update = post_mb_update self.find('mailboxes').filter = lambda mb: self.context.session.identity in ['root', mb.owner] self.binder.setup(self.manager.config) @on('new-mailbox', 'click') def on_new_mailbox(self): self.binder.update() mb = Mailbox.create() mb.local = self.find('new-mailbox-local').value mb.domain = self.find('new-mailbox-domain').value or self.find('new-mailbox-domain-custom').value mb.owner = self.context.session.identity mb.password = '' if not mb.local: self.context.notify('error', _('Invalid mailbox name')) return if not mb.domain: self.context.notify('error', _('Invalid mailbox domain')) return for existing in self.manager.config.mailboxes: if existing.name == mb.name: self.context.notify('error', _('This address is already taken')) return self.find('new-mailbox-local').value = '' self.manager.config.mailboxes.append(mb) self.manager.save() self.binder.populate() def on_page_load(self): self.refresh() def refresh(self): domains = [] for ws in VHManager.get().config.websites: if self.context.session.identity in ['root', ws.owner]: domains += [d.domain for d in ws.domains] domains = sorted(list(set(domains))) if self.find('new-mailbox-domain'): self.find('new-mailbox-domain').labels = domains + [_('Custom domain')] self.find('new-mailbox-domain').values = domains + [None] if self.manager.is_configured: self.binder.unpopulate().populate() @on('save', 'click') def save(self): self.binder.update() self.manager.save() self.refresh() self.context.notify('info', _('Saved'))
class Configurator(SectionPlugin): def init(self): self.title = _('Configure') self.icon = 'wrench' self.category = '' self.order = 50 self.append(self.ui.inflate('configurator:main')) self.binder = Binder(ajenti.config.tree, self.find('ajenti-config')) self.ccmgr = ClassConfigManager.get() self.classconfig_binding = Binder(self.ccmgr, self.find('classconfigs')) def post_classconfig_bind(object, collection, item, ui): def configure(): self.configure_plugin(item, notify=False) ui.find('configure').on('click', configure) self.find('classconfigs').find( 'classes').post_item_bind = post_classconfig_bind self.find('users').new_item = lambda c: UserData() def post_user_bind(object, collection, item, ui): provider = UserManager.get(manager.context).get_sync_provider() editable = item.name != 'root' renameable = editable and provider.allows_renaming deletable = renameable ui.find('name-edit').visible = renameable ui.find('name-label').visible = not renameable ui.find('delete').visible = deletable box = ui.find('permissions') box.empty() p = PermissionProvider.get_all() for prov in p: line = self.ui.create('tab', title=prov.get_name()) box.append(line) for perm in prov.get_permissions(): line.append( self.ui.create('checkbox', id=perm[0], text=perm[1], value=(perm[0] in item.permissions))) def copy(): self.save() newuser = deepcopy(item) newuser.name += '_' collection[newuser.name] = newuser self.refresh() ui.find('copy').on('click', copy) self.find('users').post_item_bind = post_user_bind def post_user_update(object, collection, item, ui): box = ui.find('permissions') for prov in PermissionProvider.get_all(): for perm in prov.get_permissions(): has = box.find(perm[0]).value if has and not perm[0] in item.permissions: item.permissions.append(perm[0]) if not has and perm[0] in item.permissions: item.permissions.remove(perm[0]) if ui.find('password').value: item.password = ui.find('password').value self.find('users').post_item_update = post_user_update def on_page_load(self): self.refresh() @on('sync-users-button', 'click') def on_sync_users(self): self.save() prov = UserManager.get(manager.context).get_sync_provider() try: prov.test() prov.sync() except Exception as e: self.context.notify('error', str(e)) self.refresh() @on('configure-sync-button', 'click') def on_configure_sync(self): self.save() self.configure_plugin(UserManager.get( manager.context).get_sync_provider(), notify=False) self.refresh() def refresh(self): self.binder.unpopulate() self.find('sync-providers').labels = [ x.title for x in UserSyncProvider.get_classes() ] self.find('sync-providers').values = [ x.id for x in UserSyncProvider.get_classes() ] provider = UserManager.get(manager.context).get_sync_provider() self.find('sync-providers').value = provider.id self.find('add-user-button').visible = provider.id == '' self.find('sync-users-button').visible = provider.id != '' self.find('password').visible = provider.id == '' self.find('configure-sync-button' ).visible = provider.classconfig_editor is not None try: provider.test() sync_ok = True except Exception as e: self.context.notify('error', str(e)) sync_ok = False self.find('sync-status-ok').visible = sync_ok self.find('sync-status-fail').visible = not sync_ok languages = sorted(ajenti.locales.list_locales()) self.find('language').labels = [_('Auto'), 'en_US'] + languages self.find('language').values = ['', 'en_US'] + languages self.binder.setup().populate() self.ccmgr.reload() self.classconfig_binding.setup().populate() @on('save-button', 'click') @restrict('configurator:configure') def save(self): self.binder.update() UserManager.get(manager.context).set_sync_provider( self.find('sync-providers').value) for user in ajenti.config.tree.users.values(): if not '|' in user.password: user.password = UserManager.get(manager.context).hash_password( user.password) self.refresh() ajenti.config.save() self.context.notify( 'info', _('Saved. Please restart Ajenti for changes to take effect.')) @on('fake-ssl', 'click') def on_gen_ssl(self): host = self.find('fake-ssl-host').value if host == '': self.context.notify('error', _('Please supply hostname')) else: self.gen_ssl(host) @on('restart-button', 'click') def on_restart(self): ajenti.restart() @intent('configure-plugin') def configure_plugin(self, plugin=None, notify=True): self.find('tabs').active = 1 self.refresh() if plugin and notify: self.context.notify( 'info', _('Please configure %s plugin!') % plugin.classconfig_editor.title) self.activate() dialog = self.find('classconfigs').find('dialog') dialog.find('container').empty() dialog.visible = True editor = plugin.classconfig_editor.new(self.ui) dialog.find('container').append(editor) binder = DictAutoBinding(plugin, 'classconfig', editor.find('bind')) binder.populate() def save(button=None): dialog.visible = False binder.update() plugin.save_classconfig() self.save() dialog.on('button', save) @intent('setup-fake-ssl') def gen_ssl(self, host): self.save() subprocess.call(['ajenti-ssl-gen', host, '-f']) ajenti.config.load() self.refresh()
class Filesystems(SectionPlugin): def init(self): self.title = _('Filesystems') self.icon = 'hdd' self.category = _('System') self.append(self.ui.inflate('fstab:main')) self.find('type').labels = [ 'Auto', 'EXT2', 'EXT3', 'EXT4', 'NTFS', 'FAT', 'ZFS', 'ReiserFS', 'Samba', 'None', 'Loop' ] self.find('type').values = [ 'auto', 'ext2', 'ext3', 'ext4', 'ntfs', 'vfat', 'zfs', 'reiser', 'smb', 'none', 'loop' ] self.fstab_config = FSTabConfig(path='/etc/fstab') self.mounts = MountsBackend.get() self.binder = Binder(None, self) self.find('fstab').find( 'filesystems').new_item = lambda c: FilesystemData() def post_mount_bind(object, collection, item, ui): ui.find('umount').on('click', self.on_umount, item) self.find('mounts').find( 'filesystems').post_item_bind = post_mount_bind def on_page_load(self): self.refresh() def on_umount(self, mount): subprocess.call(['umount', mount.mountpoint]) self.context.notify('info', _('Unmounted')) self.refresh() @on('mount-all', 'click') def on_mount_all(self): self.save() if subprocess.call(['mount', '-a']): self.context.notify('error', _('mount -a failed')) self.refresh() @on('refresh', 'click') def refresh(self): self.binder.unpopulate() self.reload_disks() self.fstab_config.load() self.fstab = self.fstab_config.tree self.mounts.reload() self.binder.setup(self).populate() def reload_disks(self): lst = disks.list_devices(by_uuid=True, by_id=True, by_label=True) self.find('device').labels = [x[0] for x in lst] self.find('device').values = [x[1] for x in lst] @on('save', 'click') def save(self): self.binder.update() self.fstab_config.save() self.context.notify('info', _('Saved'))
class Configurator (SectionPlugin): def init(self): self.title = _('Configure') self.icon = 'wrench' self.category = '' self.order = 50 self.append(self.ui.inflate('configurator:main')) self.binder = Binder(ajenti.config.tree, self.find('ajenti-config')) self.ccmgr = ClassConfigManager.get() self.classconfig_binding = Binder(self.ccmgr, self.find('classconfigs')) def post_classconfig_bind(object, collection, item, ui): def configure(): self.configure_plugin(item, notify=False) ui.find('configure').on('click', configure) self.find('classconfigs').find('classes').post_item_bind = post_classconfig_bind self.find('users').new_item = lambda c: UserData() def post_user_bind(object, collection, item, ui): provider = UserManager.get(manager.context).get_sync_provider() editable = item.name != 'root' renameable = editable and provider.allows_renaming deletable = renameable ui.find('name-edit').visible = renameable ui.find('name-label').visible = not renameable ui.find('delete').visible = deletable box = ui.find('permissions') box.empty() p = PermissionProvider.get_all() for prov in p: line = self.ui.create('tab', title=prov.get_name()) box.append(line) for perm in prov.get_permissions(): line.append( self.ui.create('checkbox', id=perm[0], text=perm[1], value=(perm[0] in item.permissions)) ) def copy(): self.save() newuser = deepcopy(item) newuser.name += '_' collection[newuser.name] = newuser self.refresh() ui.find('copy').on('click', copy) self.find('users').post_item_bind = post_user_bind def post_user_update(object, collection, item, ui): box = ui.find('permissions') for prov in PermissionProvider.get_all(): for perm in prov.get_permissions(): has = box.find(perm[0]).value if has and not perm[0] in item.permissions: item.permissions.append(perm[0]) if not has and perm[0] in item.permissions: item.permissions.remove(perm[0]) if ui.find('password').value: item.password = ui.find('password').value self.find('users').post_item_update = post_user_update def on_page_load(self): self.refresh() @on('sync-users-button', 'click') def on_sync_users(self): self.save() prov = UserManager.get(manager.context).get_sync_provider() try: prov.test() prov.sync() except Exception as e: self.context.notify('error', str(e)) self.refresh() @on('configure-sync-button', 'click') def on_configure_sync(self): self.save() self.configure_plugin(UserManager.get(manager.context).get_sync_provider(), notify=False) self.refresh() def refresh(self): self.binder.unpopulate() self.find('sync-providers').labels = [x.title for x in UserSyncProvider.get_classes()] self.find('sync-providers').values = [x.id for x in UserSyncProvider.get_classes()] provider = UserManager.get(manager.context).get_sync_provider() self.find('sync-providers').value = provider.id self.find('add-user-button').visible = provider.id == '' self.find('sync-users-button').visible = provider.id != '' self.find('password').visible = provider.id == '' self.find('configure-sync-button').visible = provider.classconfig_editor is not None try: provider.test() sync_ok = True except Exception as e: self.context.notify('error', str(e)) sync_ok = False self.find('sync-status-ok').visible = sync_ok self.find('sync-status-fail').visible = not sync_ok languages = sorted(ajenti.locales.list_locales()) self.find('language').labels = [_('Auto'), 'en_US'] + languages self.find('language').values = ['', 'en_US'] + languages self.binder.setup().populate() self.ccmgr.reload() self.classconfig_binding.setup().populate() @on('save-button', 'click') @restrict('configurator:configure') def save(self): self.binder.update() UserManager.get(manager.context).set_sync_provider(self.find('sync-providers').value) for user in ajenti.config.tree.users.values(): if not '|' in user.password: user.password = UserManager.get(manager.context).hash_password(user.password) self.refresh() ajenti.config.save() self.context.notify('info', _('Saved. Please restart Ajenti for changes to take effect.')) @on('fake-ssl', 'click') def on_gen_ssl(self): host = self.find('fake-ssl-host').value if host == '': self.context.notify('error', _('Please supply hostname')) else: self.gen_ssl(host) @on('restart-button', 'click') def on_restart(self): ajenti.restart() @intent('configure-plugin') def configure_plugin(self, plugin=None, notify=True): self.find('tabs').active = 1 self.refresh() if plugin and notify: self.context.notify('info', _('Please configure %s plugin!') % plugin.classconfig_editor.title) self.activate() dialog = self.find('classconfigs').find('dialog') dialog.find('container').empty() dialog.visible = True editor = plugin.classconfig_editor.new(self.ui) dialog.find('container').append(editor) binder = DictAutoBinding(plugin, 'classconfig', editor.find('bind')) binder.populate() def save(button=None): dialog.visible = False binder.update() plugin.save_classconfig() self.save() dialog.on('button', save) @intent('setup-fake-ssl') def gen_ssl(self, host): self.save() subprocess.call(['ajenti-ssl-gen', host, '-f']) ajenti.config.load() self.refresh()
class MailPlugin (SectionPlugin): def init(self): self.title = _('Mail') self.icon = 'envelope' self.category = 'Web' self.manager = MailManager.get() if not self.manager.is_configured: self.append(self.ui.inflate('vh-mail:not-configured')) else: self.post_init() @on('initial-enable', 'click') def on_initial_enable(self): self.post_init() self.manager.save() self.refresh() def post_init(self): self.empty() self.append(self.ui.inflate('vh-mail:main')) self.binder = Binder(None, self) def post_mb_bind(object, collection, item, ui): ui.find('size').text = str_fsize(self.manager.get_usage(item)) def post_mb_update(object, collection, item, ui): if ui.find('password').value: item.password = ui.find('password').value self.find('mailboxes').post_item_bind = post_mb_bind self.find('mailboxes').post_item_update = post_mb_update self.find('mailboxes').filter = \ lambda mb: self.context.session.identity in ['root', mb.owner] self.find('targets').new_item = lambda c: ForwardingTarget.create() self.binder.setup(self.manager.config) def _fetch_new_mailbox_name(self, cls): mb = cls.create() mb.local = self.find('new-mailbox-local').value mb.domain = self.find('new-mailbox-domain').value or \ self.find('new-mailbox-domain-custom').value if not mb.local: self.context.notify('error', _('Invalid mailbox name')) return if not mb.domain: self.context.notify('error', _('Invalid mailbox domain')) return if cls == ForwardingMailbox: for existing in self.manager.config.forwarding_mailboxes: if existing.name == mb.name: self.context.notify( 'error', _('This address is already taken') ) return else: for existing in self.manager.config.mailboxes: if existing.name == mb.name: self.context.notify( 'error', _('This address is already taken') ) return self.find('new-mailbox-local').value = '' return mb @on('new-mailbox', 'click') def on_new_mailbox(self): self.binder.update() mb = self._fetch_new_mailbox_name(Mailbox) if not mb: return mb.owner = self.context.session.identity mb.password = '' self.manager.config.mailboxes.append(mb) self.manager.save() self.binder.populate() @on('new-forwarding-mailbox', 'click') def on_new_forwarding_mailbox(self): self.binder.update() mb = self._fetch_new_mailbox_name(ForwardingMailbox) if not mb: return mb.owner = self.context.session.identity self.manager.config.forwarding_mailboxes.append(mb) self.manager.save() self.binder.populate() def on_page_load(self): self.refresh() def refresh(self): if not self.manager.is_configured: return domains = [] for ws in VHManager.get().config.websites: if self.context.session.identity in ['root', ws.owner]: domains += [d.domain for d in ws.domains] domains = sorted(list(set(domains))) if self.find('new-mailbox-domain'): self.find('new-mailbox-domain').labels = \ domains + [_('Custom domain')] self.find('new-mailbox-domain').values = domains + [None] if self.manager.is_configured: self.binder.unpopulate().populate() if os.path.exists(self.manager.config.dkim_private_key): pubkey = subprocess.check_output([ 'openssl', 'rsa', '-in', self.manager.config.dkim_private_key, '-pubout' ]) pubkey = filter(None, pubkey.split('-'))[1].replace('\n', '') dns = '@\t\t\t\t10800 IN TXT "v=spf1 a -all"\n' dns += '_domainkey\t\t10800 IN TXT "o=~; r=postmaster@<domain>"\n' dns += '%s._domainkey\t10800 IN TXT "v=DKIM1; k=rsa; p=%s"\n' % ( self.manager.config.dkim_selector, pubkey ) dns += '_dmarc\t\t\t10800 IN TXT "v=DMARC1; p=quarantine"\n' self.find('dkim-domain-entry').value = dns else: self.find('dkim-domain-entry').value = _('No valid key exists') @on('generate-dkim-key', 'click') def on_generate_dkim_key(self): self.binder.update() self.manager.generate_dkim_key() self.binder.populate() self.save() @on('generate-tls-cert', 'click') def on_generate_tls_cert(self): self.binder.update() self.manager.generate_tls_cert() self.binder.populate() self.save() @on('save', 'click') def save(self): self.binder.update() self.manager.save() self.refresh() self.context.notify('info', _('Saved'))
class MailPlugin(SectionPlugin): def init(self): self.title = _("Mail") self.icon = "envelope" self.category = "Web" self.manager = MailManager.get() if not self.manager.is_configured: self.append(self.ui.inflate("vh-mail:not-configured")) else: self.post_init() @on("initial-enable", "click") def on_initial_enable(self): self.post_init() self.manager.save() self.refresh() def post_init(self): self.empty() self.append(self.ui.inflate("vh-mail:main")) self.binder = Binder(None, self) def post_mb_bind(object, collection, item, ui): ui.find("size").text = str_fsize(self.manager.get_usage(item)) def post_mb_update(object, collection, item, ui): if ui.find("password").value: item.password = ui.find("password").value self.find("mailboxes").post_item_bind = post_mb_bind self.find("mailboxes").post_item_update = post_mb_update self.find("mailboxes").filter = lambda mb: self.context.session.identity in ["root", mb.owner] self.find("targets").new_item = lambda c: ForwardingTarget.create() self.binder.setup(self.manager.config) def _fetch_new_mailbox_name(self, cls): mb = cls.create() mb.local = self.find("new-mailbox-local").value mb.domain = self.find("new-mailbox-domain").value or self.find("new-mailbox-domain-custom").value if not mb.local: self.context.notify("error", _("Invalid mailbox name")) return if not mb.domain: self.context.notify("error", _("Invalid mailbox domain")) return for existing in self.manager.config.mailboxes: if existing.name == mb.name: self.context.notify("error", _("This address is already taken")) return self.find("new-mailbox-local").value = "" return mb @on("new-mailbox", "click") def on_new_mailbox(self): self.binder.update() mb = self._fetch_new_mailbox_name(Mailbox) if not mb: return mb.owner = self.context.session.identity mb.password = "" self.manager.config.mailboxes.append(mb) self.manager.save() self.binder.populate() @on("new-forwarding-mailbox", "click") def on_new_forwarding_mailbox(self): self.binder.update() mb = self._fetch_new_mailbox_name(ForwardingMailbox) if not mb: return mb.owner = self.context.session.identity self.manager.config.forwarding_mailboxes.append(mb) self.manager.save() self.binder.populate() def on_page_load(self): self.refresh() def refresh(self): if not self.manager.is_configured: return domains = [] for ws in VHManager.get().config.websites: if self.context.session.identity in ["root", ws.owner]: domains += [d.domain for d in ws.domains] domains = sorted(list(set(domains))) if self.find("new-mailbox-domain"): self.find("new-mailbox-domain").labels = domains + [_("Custom domain")] self.find("new-mailbox-domain").values = domains + [None] if self.manager.is_configured: self.binder.unpopulate().populate() if os.path.exists(self.manager.config.dkim_private_key): pubkey = subprocess.check_output(["openssl", "rsa", "-in", self.manager.config.dkim_private_key, "-pubout"]) pubkey = filter(None, pubkey.split("-"))[1].replace("\n", "") dns = '@\t\t\t\t10800 IN TXT "v=spf1 a -all"\n' dns += '_domainkey\t\t10800 IN TXT "o=~; r=postmaster@<domain>"\n' dns += '%s._domainkey\t10800 IN TXT "v=DKIM1; k=rsa; p="%s"\n' % (self.manager.config.dkim_selector, pubkey) dns += '_dmarc\t\t\t10800 IN TXT "v=DMARC1; p=quarantine; sp=r"\n' self.find("dkim-domain-entry").value = dns else: self.find("dkim-domain-entry").value = _("No valid key exists") @on("generate-dkim-key", "click") def on_generate_dkim_key(self): self.binder.update() self.manager.generate_dkim_key() self.binder.populate() self.save() @on("generate-tls-cert", "click") def on_generate_tls_cert(self): self.binder.update() self.manager.generate_tls_cert() self.binder.populate() self.save() @on("save", "click") def save(self): self.binder.update() self.manager.save() self.refresh() self.context.notify("info", _("Saved"))
class MailPlugin(SectionPlugin): def init(self): self.title = _('Mail') self.icon = 'envelope' self.category = 'Web' self.manager = MailManager.get() if not self.manager.is_configured: self.append(self.ui.inflate('vh-mail:not-configured')) else: self.post_init() @on('initial-enable', 'click') def on_initial_enable(self): self.post_init() self.manager.save() self.refresh() def post_init(self): self.empty() self.append(self.ui.inflate('vh-mail:main')) self.binder = Binder(None, self) def post_mb_bind(object, collection, item, ui): ui.find('size').text = str_fsize(self.manager.get_usage(item)) def post_mb_update(object, collection, item, ui): if ui.find('password').value: item.password = ui.find('password').value self.find('mailboxes').post_item_bind = post_mb_bind self.find('mailboxes').post_item_update = post_mb_update self.binder.setup(self.manager.config) @on('new-mailbox', 'click') def on_new_mailbox(self): self.binder.update() mb = Mailbox.create() mb.local = self.find('new-mailbox-local').value mb.domain = self.find('new-mailbox-domain').value or self.find( 'new-mailbox-domain-custom').value mb.password = '' self.find('new-mailbox-local').value = '' if not mb.local: self.context.error(_('Invalid mailbox name')) if not mb.domain: self.context.error(_('Invalid mailbox domain')) self.manager.config.mailboxes.append(mb) self.manager.save() self.binder.populate() def on_page_load(self): self.refresh() def refresh(self): domains = [] for ws in VHManager.get().config.websites: domains += [d.domain for d in ws.domains] domains = sorted(list(set(domains))) self.find('new-mailbox-domain').labels = domains + [_('Custom domain')] self.find('new-mailbox-domain').values = domains + [None] if self.manager.is_configured: self.binder.unpopulate().populate() @on('save', 'click') def save(self): self.binder.update() self.manager.save() self.refresh() self.context.notify('info', _('Saved'))
class DBPlugin(SectionPlugin): service_name = "" service_buttons = [] has_users = True def init(self): self.append(self.ui.inflate("db_common:main")) self.binder = Binder(None, self) self.find_type("servicebar").buttons = self.service_buttons def delete_db(db, c): self.query_drop(db) self.refresh() self.find("databases").delete_item = delete_db def delete_user(user, c): self.query_drop_user(user) self.refresh() self.find("users").delete_item = delete_user def on_page_load(self): self.refresh() @on("sql-run", "click") def on_sql_run(self): try: result = self.query_sql(self.find("sql-db").value, self.find("sql-input").value) self.context.notify("info", _("Query finished")) except Exception as e: self.context.notify("error", str(e)) return tbl = self.find("sql-output") tbl.empty() if len(result) > 200: self.context.notify("info", _("Output cut from %i rows to 200") % len(result)) result = result[:200] for row in result: erow = self.ui.create("dtr") tbl.append(erow) for cell in row: ecell = self.ui.create("dtd") ecell.append(self.ui.create("label", text=str(cell))) erow.append(ecell) @on("add-db", "click") def on_add_db(self): self.find("db-name-dialog").value = "" self.find("db-name-dialog").visible = True @on("add-user", "click") def on_add_user(self): self.find("add-user-dialog").visible = True def refresh(self): self.databases = [] self.users = [] try: self.databases = self.query_databases() if self.has_users: self.users = self.query_users() except Exception as e: import traceback traceback.print_exc() self.context.notify("error", str(e)) if hasattr(self, "config_class"): self.context.launch("configure-plugin", plugin=self.config_class.get()) return self.binder.unpopulate() self.find("sql-db").labels = self.find("sql-db").values = [x.name for x in self.databases] self.binder.setup(self).populate() self.find_type("servicebar").reload() @on("db-name-dialog", "submit") def on_db_name_dialog_submit(self, value=None): try: self.query_create(value) except Exception as e: self.context.notify("error", str(e)) return self.refresh() @on("add-user-dialog", "button") def on_add_user_dialog(self, button=None): d = self.find("add-user-dialog") d.visible = False if button == "ok": u = User() u.name = d.find("name").value u.host = d.find("host").value u.password = d.find("password").value try: self.query_create_user(u) except Exception as e: self.context.notify("error", str(e)) return self.refresh() def query_sql(self, db, sql): raise NotImplementedError() def query_databases(self): raise NotImplementedError() def query_drop(self, db): raise NotImplementedError() def query_create(self, name): raise NotImplementedError() def query_users(self): raise NotImplementedError() def query_create_user(self, user): raise NotImplementedError() def query_drop_user(self, user): raise NotImplementedError()
class Tasks (SectionPlugin): def init(self): self.title = _('Tasks') self.icon = 'cog' self.category = _('Tools') self.append(self.ui.inflate('tasks:main')) self.manager = TaskManager.get() self.binder = Binder(None, self) def post_td_bind(object, collection, item, ui): if item.get_class(): params_ui = self.ui.inflate(item.get_class().ui) item.binder = DictAutoBinding(item, 'params', params_ui.find('bind')) item.binder.populate() ui.find('slot').empty() ui.find('slot').append(params_ui) def post_td_update(object, collection, item, ui): if hasattr(item, 'binder'): item.binder.update() def post_rt_bind(object, collection, item, ui): def abort(): item.abort() self.refresh() ui.find('abort').on('click', abort) self.find('task_definitions').post_item_bind = post_td_bind self.find('task_definitions').post_item_update = post_td_update self.find('running_tasks').post_item_bind = post_rt_bind self.find('job_definitions').new_item = lambda c: JobDefinition() def on_page_load(self): self.refresh() @on('refresh', 'click') def refresh(self): self.manager.refresh() self.binder.unpopulate() dd = self.find('task-classes') dd.labels = [] dd.values = [] for task in Task.get_classes(): if not task.hidden: dd.labels.append(task.name) dd.values.append(task.classname) dd = self.find('task-selector') dd.labels = [_.name for _ in self.manager.task_definitions] dd.values = [_.id for _ in self.manager.task_definitions] self.find('run-task-selector').labels = dd.labels self.find('run-task-selector').values = dd.values self.binder.setup(self.manager).populate() @on('run-task', 'click') def on_run_task(self): self.manager.run(task_id=self.find('run-task-selector').value, context=self.context) self.refresh() @on('create-task', 'click') def on_create_task(self): cls = self.find('task-classes').value td = TaskDefinition(task_class=cls) td.name = td.get_class().name self.manager.task_definitions.append(td) self.refresh() @on('save', 'click') def on_save(self): self.binder.update() self.manager.save() self.refresh()
class DBPlugin (SectionPlugin): service_name = '' service_buttons = [] has_users = True def init(self): self.append(self.ui.inflate('db_common:main')) self.binder = Binder(None, self) self.find_type('servicebar').buttons = self.service_buttons def delete_db(db, c): self.query_drop(db) self.refresh() self.find('databases').delete_item = delete_db def delete_user(user, c): self.query_drop_user(user) self.refresh() self.find('users').delete_item = delete_user def on_page_load(self): self.refresh() @on('sql-run', 'click') def on_sql_run(self): try: result = self.query_sql(self.find('sql-db').value, self.find('sql-input').value) self.context.notify('info', _('Query finished')) except Exception as e: self.context.notify('error', str(e)) return tbl = self.find('sql-output') tbl.empty() if len(result) > 200: self.context.notify('info', _('Output cut from %i rows to 200') % len(result)) result = result[:200] for row in result: erow = self.ui.create('dtr') tbl.append(erow) for cell in row: ecell = self.ui.create('dtd') ecell.append(self.ui.create('label', text=str(cell))) erow.append(ecell) @on('add-db', 'click') def on_add_db(self): self.find('db-name-dialog').value = '' self.find('db-name-dialog').visible = True @on('add-user', 'click') def on_add_user(self): self.find('add-user-dialog').visible = True def refresh(self): self.binder.setup(self).populate() self.databases = [] self.users = [] try: self.databases = self.query_databases() if self.has_users: self.users = self.query_users() except Exception as e: import traceback; traceback.print_exc(); self.context.notify('error', str(e)) if hasattr(self, 'config_class'): self.context.launch('configure-plugin', plugin=self.config_class.get()) return self.binder.unpopulate() self.find('sql-db').labels = self.find('sql-db').values = [x.name for x in self.databases] self.binder.populate() self.find_type('servicebar').reload() @on('db-name-dialog', 'submit') def on_db_name_dialog_submit(self, value=None): try: self.query_create(value) except Exception as e: self.context.notify('error', str(e)) return self.refresh() @on('add-user-dialog', 'button') def on_add_user_dialog(self, button=None): d = self.find('add-user-dialog') d.visible = False if button == 'ok': u = User() u.name = d.find('name').value u.host = d.find('host').value u.password = d.find('password').value try: self.query_create_user(u) except Exception as e: self.context.notify('error', str(e)) return self.refresh() def query_sql(self, db, sql): raise NotImplementedError() def query_databases(self): raise NotImplementedError() def query_drop(self, db): raise NotImplementedError() def query_create(self, name): raise NotImplementedError() def query_users(self): raise NotImplementedError() def query_create_user(self, user): raise NotImplementedError() def query_drop_user(self, user): raise NotImplementedError()
class Tasks(SectionPlugin): def init(self): self.title = _("Tasks") self.icon = "cog" self.category = _("Tools") self.append(self.ui.inflate("tasks:main")) self.manager = TaskManager.get(manager.context) self.binder = Binder(None, self) def post_td_bind(object, collection, item, ui): if item.get_class(): params_ui = self.ui.inflate(item.get_class().ui) item.binder = DictAutoBinding(item, "params", params_ui.find("bind")) item.binder.populate() ui.find("slot").empty() ui.find("slot").append(params_ui) def post_td_update(object, collection, item, ui): if hasattr(item, "binder"): item.binder.update() def post_rt_bind(object, collection, item, ui): def abort(): item.abort() self.refresh() ui.find("abort").on("click", abort) self.find("task_definitions").post_item_bind = post_td_bind self.find("task_definitions").post_item_update = post_td_update self.find("running_tasks").post_item_bind = post_rt_bind self.find("job_definitions").new_item = lambda c: JobDefinition() def on_page_load(self): self.refresh() @on("refresh", "click") def refresh(self): self.manager.refresh() self.binder.unpopulate() dd = self.find("task-classes") dd.labels = [] dd.values = [] for task in Task.get_classes(): if not task.hidden: dd.labels.append(task.name) dd.values.append(task.classname) dd = self.find("task-selector") dd.labels = [_.name for _ in self.manager.task_definitions] dd.values = [_.id for _ in self.manager.task_definitions] self.find("run-task-selector").labels = dd.labels self.find("run-task-selector").values = dd.values self.binder.setup(self.manager).populate() @on("run-task", "click") def on_run_task(self): self.manager.run(task_id=self.find("run-task-selector").value, context=self.context) self.refresh() @on("create-task", "click") def on_create_task(self): cls = self.find("task-classes").value td = TaskDefinition(task_class=cls) td.name = td.get_class().name self.manager.task_definitions.append(td) self.refresh() @on("save", "click") def on_save(self): self.binder.update() self.manager.save() self.refresh()
class WebsitesPlugin (SectionPlugin): def init(self): self.title = _('Websites') self.icon = 'globe' self.category = 'Web' self.manager = VHManager.get() if not self.manager.is_configured: from ajenti.plugins.vh import destroyed_configs self.append(self.ui.inflate('vh:not-configured')) self.find('destroyed-configs').text = ', '.join(destroyed_configs) else: self.post_init() @on('initial-enable', 'click') def on_initial_enable(self): self.post_init() self.manager.save() self.refresh() def post_init(self): self.empty() self.append(self.ui.inflate('vh:main')) self.binder = Binder(None, self) def post_ws_bind(object, collection, item, ui): def manage(): self.context.launch('v:manage-website', website=item) ui.find('manage').on('click', manage) self.find('websites').post_item_bind = post_ws_bind self.binder.setup(self.manager.config) @on('new-website', 'click') def on_new_website(self): self.binder.update() name = self.find('new-website-name').value self.find('new-website-name').value = '' if not name: name = '_' slug = slugify(name) slugs = [x.slug for x in self.manager.config.websites] while slug in slugs: slug += '_' w = Website.create(name) w.slug = slug self.manager.config.websites.append(w) self.manager.save() self.binder.populate() def on_page_load(self): self.refresh() def refresh(self): if self.manager.is_configured: self.binder.unpopulate().populate() @on('save', 'click') def save(self): self.binder.update() self.context.endpoint.send_progress(_('Saving changes')) self.manager.save() self.context.endpoint.send_progress(_('Applying changes')) self.manager.update_configuration() self.refresh() self.context.notify('info', _('Saved'))
class Tasks(SectionPlugin): def init(self): self.title = _('Tasks') self.icon = 'cog' self.category = _('Tools') self.append(self.ui.inflate('tasks:main')) self.manager = TaskManager.get() self.binder = Binder(None, self) def post_td_bind(object, collection, item, ui): if item.get_class(): params_ui = self.ui.inflate(item.get_class().ui) item.binder = DictAutoBinding(item, 'params', params_ui.find('bind')) item.binder.populate() ui.find('slot').empty() ui.find('slot').append(params_ui) def post_td_update(object, collection, item, ui): if hasattr(item, 'binder'): item.binder.update() def post_rt_bind(object, collection, item, ui): def abort(): item.abort() self.refresh() ui.find('abort').on('click', abort) self.find('task_definitions').post_item_bind = post_td_bind self.find('task_definitions').post_item_update = post_td_update self.find('running_tasks').post_item_bind = post_rt_bind self.find('job_definitions').new_item = lambda c: JobDefinition() def on_page_load(self): self.refresh() @on('refresh', 'click') def refresh(self): self.manager.refresh() self.binder.unpopulate() dd = self.find('task-classes') dd.labels = [] dd.values = [] for task in Task.get_classes(): if not task.hidden: dd.labels.append(task.name) dd.values.append(task.classname) dd = self.find('task-selector') dd.labels = [_.name for _ in self.manager.task_definitions] dd.values = [_.id for _ in self.manager.task_definitions] self.find('run-task-selector').labels = dd.labels self.find('run-task-selector').values = dd.values self.binder.setup(self.manager).populate() @on('run-task', 'click') def on_run_task(self): self.manager.run(task_id=self.find('run-task-selector').value, context=self.context) self.refresh() @on('create-task', 'click') def on_create_task(self): cls = self.find('task-classes').value td = TaskDefinition(task_class=cls) td.name = td.get_class().name self.manager.task_definitions.append(td) self.refresh() @on('save', 'click') def on_save(self): self.binder.update() self.manager.save() self.refresh()
class WebsitesPlugin(SectionPlugin): def init(self): self.title = _('Websites') self.icon = 'globe' self.category = 'Web' self.manager = VHManager.get() if not self.manager.is_configured: from ajenti.plugins.vh import destroyed_configs self.append(self.ui.inflate('vh:not-configured')) self.find('destroyed-configs').text = ', '.join(destroyed_configs) else: self.post_init() @on('initial-enable', 'click') def on_initial_enable(self): self.post_init() self.manager.save() self.refresh() def post_init(self): self.empty() self.append(self.ui.inflate('vh:main')) self.binder = Binder(None, self) def post_ws_bind(object, collection, item, ui): def manage(): self.context.launch('v:manage-website', website=item) ui.find('manage').on('click', manage) self.find('websites').post_item_bind = post_ws_bind self.binder.setup(self.manager.config) @on('new-website', 'click') def on_new_website(self): self.binder.update() name = self.find('new-website-name').value self.find('new-website-name').value = '' if not name: name = '_' slug = slugify(name) slugs = [x.slug for x in self.manager.config.websites] while slug in slugs: slug += '_' w = Website.create(name) w.slug = slug self.manager.config.websites.append(w) self.manager.save() self.binder.populate() def on_page_load(self): self.refresh() def refresh(self): if self.manager.is_configured: self.binder.unpopulate().populate() @on('save', 'click') def save(self): self.binder.update() self.context.endpoint.send_progress(_('Saving changes')) self.manager.save() self.context.endpoint.send_progress(_('Applying changes')) self.manager.update_configuration() self.refresh() self.context.notify('info', _('Saved'))