<commit_before>import os
import shlex
from urlparse import urlparse
from pkg_resources import resource_string
from dateutil.parser import parse as date_parse
from dateutil.relativedelta import relativedelta as date_delta

from glob import iglob
from lacli.adf import (load_archive, make_adf, Certificate, Archive,
                       Meta, Links, Cipher, Signature, as_json)
from lacli.log import getLogger
from lacli.archive import dump_archive, archive_slug
from lacli.exceptions import InvalidArchiveError
from lacli.decorators import contains
from urllib import pathname2url
from tempfile import NamedTemporaryFile
from binascii import b2a_hex
from itertools import izip, imap
from subprocess import check_call

def group(it, n, dl):
    return imap(dl.join, izip(*[it]*n))

def pairs(it, dl=""):
    return group(it, 2, dl)

def fours(it, dl=" "):
    return group(it, 4, dl)

class Cache(object):
    def __init__(self, home):
        self.home = home

    def _cache_dir(self, path, write=False):
        dname = os.path.join(self.home, path)
        if not os.path.exists(dname) and write:
            os.makedirs(dname, mode=0744)
        return dname

    def _archive_open(self, name, mode='r'):
        dname = self._cache_dir('archives', write='w' in mode)
        return open(os.path.join(dname, name), mode)

    def _cert_open(self, name, mode='r'):
        dname = self._cache_dir('certs', write='w' in mode)
        return open(os.path.join(dname, name), mode)

    def _upload_open(self, name, mode='r'):
        dname = self._cache_dir('uploads', write='w' in mode)
        return open(os.path.join(dname, name), mode)

    @contains(dict)
    def _for_adf(self, category):
        for fn in iglob(os.path.join(self._cache_dir(category), '*.adf')):
            with open(fn) as f:
                try:
                    yield (fn, load_archive(f))
                except InvalidArchiveError:
                    getLogger().debug(fn, exc_info=True)

    def prepare(self, title, folder, fmt='zip', cb=None):
        archive = Archive(title, Meta(fmt, Cipher('aes-256-ctr', 1)))
        cert = Certificate()
        tmpdir = self._cache_dir('data', write=True)
        name, path, auth = dump_archive(archive, folder, cert, cb, tmpdir)
        link = Links(local=pathname2url(os.path.relpath(path, self.home)))
        archive.meta.size = os.path.getsize(path)
        tmpargs = {'delete': False,
                   'dir': self._cache_dir('archives', write=True)}
        with NamedTemporaryFile(prefix=name, suffix=".adf", **tmpargs) as f:
            make_adf([archive, cert, auth, link], out=f)

    def save_upload(self, fname, docs, upload):
        docs['links'].upload = upload['uri']
        docs['archive'].meta.email = upload['account']['email']
        docs['archive'].meta.name = upload['account']['displayname']
        with open(fname, 'w') as f:
            make_adf(list(docs.itervalues()), out=f)
        return {
            'fname': fname,
            'link': docs['links'].upload,
            'archive': docs['archive']
        }

    def upload_complete(self, fname, status):
        """
        adds the archive key to the signature part of the ADF file
        """
        assert 'archive_key' in status, "no archive key"
        docs = []
        with open(fname) as _upload:
            docs = load_archive(_upload)
        docs['signature'] = Signature(aid=status['archive_key'],
                                      uri='http://longaccess.com/a/')
        with open(fname, 'w') as _upload:
            make_adf(list(docs.itervalues()), out=_upload)
        return docs

    def save_cert(self, docs):
        """
        write cert documents to the cache directory under a unique filename.
        """
        fname = archive_slug(docs['archive'])
        tmpargs = {'delete': False,
                   'dir': self._cache_dir('certs', write=True)}
        with NamedTemporaryFile(prefix=fname, suffix=".adf", **tmpargs) as f:
            make_adf(list(docs.itervalues()), out=f)
        return docs['signature'].aid

    def import_cert(self, fname):
        with open(fname) as cert:
            docs = load_archive(cert)
            self.save_cert(docs)
            return docs['signature'].aid

    def _printable_cert(self, docs):
        archive = docs['archive']
        cipher = archive.meta.cipher
        if hasattr(cipher, 'mode'):
            cipher = cipher.mode
        created = date_parse(archive.meta.created)
        expires = created + date_delta(years=30)
        md5 = b2a_hex(docs['auth'].md5).upper()
        key = b2a_hex(docs['cert'].key).upper()
        hk = pairs(fours(pairs(iter(key))), " . ")

        return resource_string(__name__, "data/certificate.html").format(
            json=as_json(docs),
            aid=docs['links'].download,
            keyB=next(hk),
            keyC=next(hk),
            keyD=next(hk),
            keyE=next(hk),
            name=archive.meta.name,
            email=archive.meta.email,
            uploaded=created.strftime("%c"),
            expires=expires.strftime("%c"),
            title=archive.title,
            desc=archive.description,
            md5=" . ".join(fours(pairs(iter(md5)))),
            fmt=archive.meta.format,
            cipher=cipher)

    def shred_file(self, fname, srm=None):
        commands = []
        if srm:
            commands.append(srm)
        else:
            commands.append('srm')
            commands.append('shred')
            commands.append('gshred')
            commands.append('sdelete')
            commands.append('Eraser.exe addtask --schedule=now -q --file={file}')
        for command in commands:
            try:
                newcommand = command.format(file=fname)
                args = shlex.split(newcommand)
                if command == newcommand:
                    args.append(fname)
                if 0 == check_call(args):
                    getLogger().debug("success running {}".format(command))
                    if os.path.exists(fname):
                        os.unlink(fname)
            except Exception:
                getLogger().debug("error running {}".format(command),
                                  exc_info=True)

    def shred_cert(self, aid, countdown=[], srm=None):
        path = None
        for fname, docs in self._for_adf('certs').iteritems():
            if 'links' in docs and aid == docs['links'].download:
                path = fname
            elif 'signature' in docs and aid == docs['signature'].aid:
                path = fname
        if path:
            for a in countdown:
                pass
            self.shred_file(path, srm)
            return path

    def print_cert(self, aid):
        for fname, docs in self._for_adf('certs').iteritems():
            if 'links' in docs and aid == docs['links'].download:
                html = 'longaccess-{}.html'.format(aid)
                with open(html, 'w') as f:
                    f.write(self._printable_cert(docs))
                return html

    @contains(dict)
    def certs(self, files=[]):
        if not files:
            files = iglob(os.path.join(self._cache_dir('certs'), '*.adf'))
        for f in files:
            with open(f) as fh:
                try:
                    docs = load_archive(fh)
                    if 'signature' in docs:
                        yield (docs['signature'].aid, docs)
                except InvalidArchiveError:
                    getLogger().debug(f, exc_info=True)

    def data_file(self, link):
        try:
            parsed = urlparse(link.local)
            assert not parsed.scheme or parsed.scheme == 'file'
            return os.path.join(self.home, parsed.path)
        except:
            return None

<commit_msg>add utility to cache modulke to verify md5 sums<commit_after>import os
import shlex
from urlparse import urlparse
from pkg_resources import resource_string
from dateutil.parser import parse as date_parse
from dateutil.relativedelta import relativedelta as date_delta

from glob import iglob
from lacli.adf import (load_archive, make_adf, Certificate, Archive,
                       Meta, Links, Cipher, Signature, as_json)
from lacli.log import getLogger
from lacli.archive import dump_archive, archive_slug
from lacli.exceptions import InvalidArchiveError
from lacli.decorators import contains
from urllib import pathname2url
from tempfile import NamedTemporaryFile
from binascii import b2a_hex
from itertools import izip, imap
from subprocess import check_call

def group(it, n, dl):
    return imap(dl.join, izip(*[it]*n))

def pairs(it, dl=""):
    return group(it, 2, dl)

def fours(it, dl=" "):
    return group(it, 4, dl)

class Cache(object):
    def __init__(self, home):
        self.home = home

    def _cache_dir(self, path, write=False):
        dname = os.path.join(self.home, path)
        if not os.path.exists(dname) and write:
            os.makedirs(dname, mode=0744)
        return dname

    def _archive_open(self, name, mode='r'):
        dname = self._cache_dir('archives', write='w' in mode)
        return open(os.path.join(dname, name), mode)

    def _cert_open(self, name, mode='r'):
        dname = self._cache_dir('certs', write='w' in mode)
        return open(os.path.join(dname, name), mode)

    def _upload_open(self, name, mode='r'):
        dname = self._cache_dir('uploads', write='w' in mode)
        return open(os.path.join(dname, name), mode)

    @contains(dict)
    def _for_adf(self, category):
        for fn in iglob(os.path.join(self._cache_dir(category), '*.adf')):
            with open(fn) as f:
                try:
                    yield (fn, load_archive(f))
                except InvalidArchiveError:
                    getLogger().debug(fn, exc_info=True)

    def prepare(self, title, folder, fmt='zip', cb=None):
        archive = Archive(title, Meta(fmt, Cipher('aes-256-ctr', 1)))
        cert = Certificate()
        tmpdir = self._cache_dir('data', write=True)
        name, path, auth = dump_archive(archive, folder, cert, cb, tmpdir)
        link = Links(local=pathname2url(os.path.relpath(path, self.home)))
        archive.meta.size = os.path.getsize(path)
        tmpargs = {'delete': False,
                   'dir': self._cache_dir('archives', write=True)}
        with NamedTemporaryFile(prefix=name, suffix=".adf", **tmpargs) as f:
            make_adf([archive, cert, auth, link], out=f)

    def save_upload(self, fname, docs, upload):
        docs['links'].upload = upload['uri']
        docs['archive'].meta.email = upload['account']['email']
        docs['archive'].meta.name = upload['account']['displayname']
        with open(fname, 'w') as f:
            make_adf(list(docs.itervalues()), out=f)
        return {
            'fname': fname,
            'link': docs['links'].upload,
            'archive': docs['archive']
        }

    def upload_complete(self, fname, status):
        """
        adds the archive key to the signature part of the ADF file
        """
        assert 'archive_key' in status, "no archive key"
        docs = []
        with open(fname) as _upload:
            docs = load_archive(_upload)
        docs['signature'] = Signature(aid=status['archive_key'],
                                      uri='http://longaccess.com/a/')
        with open(fname, 'w') as _upload:
            make_adf(list(docs.itervalues()), out=_upload)
        return docs

    def save_cert(self, docs):
        """
        write cert documents to the cache directory under a unique filename.
        """
        fname = archive_slug(docs['archive'])
        tmpargs = {'delete': False,
                   'dir': self._cache_dir('certs', write=True)}
        with NamedTemporaryFile(prefix=fname, suffix=".adf", **tmpargs) as f:
            make_adf(list(docs.itervalues()), out=f)
        return docs['signature'].aid

    def import_cert(self, fname):
        with open(fname) as cert:
            docs = load_archive(cert)
            self.save_cert(docs)
            return docs['signature'].aid

    def _printable_cert(self, docs):
        archive = docs['archive']
        cipher = archive.meta.cipher
        if hasattr(cipher, 'mode'):
            cipher = cipher.mode
        created = date_parse(archive.meta.created)
        expires = created + date_delta(years=30)
        md5 = b2a_hex(docs['auth'].md5).upper()
        key = b2a_hex(docs['cert'].key).upper()
        hk = pairs(fours(pairs(iter(key))), " . ")

        return resource_string(__name__, "data/certificate.html").format(
            json=as_json(docs),
            aid=docs['links'].download,
            keyB=next(hk),
            keyC=next(hk),
            keyD=next(hk),
            keyE=next(hk),
            name=archive.meta.name,
            email=archive.meta.email,
            uploaded=created.strftime("%c"),
            expires=expires.strftime("%c"),
            title=archive.title,
            desc=archive.description,
            md5=" . ".join(fours(pairs(iter(md5)))),
            fmt=archive.meta.format,
            cipher=cipher)

    def shred_file(self, fname, srm=None):
        commands = []
        if srm:
            commands.append(srm)
        else:
            commands.append('srm')
            commands.append('shred')
            commands.append('gshred')
            commands.append('sdelete')
            commands.append('Eraser.exe addtask --schedule=now -q --file={file}')
        for command in commands:
            try:
                newcommand = command.format(file=fname)
                args = shlex.split(newcommand)
                if command == newcommand:
                    args.append(fname)
                if 0 == check_call(args):
                    getLogger().debug("success running {}".format(command))
                    if os.path.exists(fname):
                        os.unlink(fname)
            except Exception:
                getLogger().debug("error running {}".format(command),
                                  exc_info=True)

    def shred_cert(self, aid, countdown=[], srm=None):
        path = None
        for fname, docs in self._for_adf('certs').iteritems():
            if 'links' in docs and aid == docs['links'].download:
                path = fname
            elif 'signature' in docs and aid == docs['signature'].aid:
                path = fname
        if path:
            for a in countdown:
                pass
            self.shred_file(path, srm)
            return path

    def print_cert(self, aid):
        for fname, docs in self._for_adf('certs').iteritems():
            if 'links' in docs and aid == docs['links'].download:
                html = 'longaccess-{}.html'.format(aid)
                with open(html, 'w') as f:
                    f.write(self._printable_cert(docs))
                return html

    @contains(dict)
    def certs(self, files=[]):
        if not files:
            files = iglob(os.path.join(self._cache_dir('certs'), '*.adf'))
        for f in files:
            with open(f) as fh:
                try:
                    docs = load_archive(fh)
                    if 'signature' in docs:
                        yield (docs['signature'].aid, docs)
                except InvalidArchiveError:
                    getLogger().debug(f, exc_info=True)

    def data_file(self, link):
        try:
            parsed = urlparse(link.local)
            assert not parsed.scheme or parsed.scheme == 'file'
            return os.path.join(self.home, parsed.path)
        except:
            return None

if __name__ == "__main__":
    import sys
    import hashlib
    cache = Cache(os.path.expanduser(os.path.join("~", ".longaccess")))
    for fname, docs in cache._for_adf('archives').iteritems():
        path = os.path.join(cache.home, docs['links'].local)
        with open(path) as f:
            md5 = hashlib.md5()
            while 1:
                 buf = f.read(16*1024)
                 if not buf:
                     break
                 md5.update(buf)
            assert md5.digest() == docs['auth'].md5, path
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""Page Admin module."""
from pages import settings
from pages.models import Page, Content, PageAlias
from pages.http import get_language_from_request, get_template_from_request
from pages.utils import get_placeholders
from pages.templatetags.pages_tags import PlaceholderNode
from pages.admin.utils import get_connected, make_inline_admin
from pages.admin.forms import PageForm
from pages.admin.views import traduction, get_content, sub_menu
from pages.admin.views import list_pages_ajax
from pages.admin.views import change_status, modify_content, delete_content
from pages.admin.views import move_page
from pages.admin.actions import export_pages_as_json, import_pages_from_json
from pages.permissions import PagePermission
from pages.http import auto_render
import pages.widgets

from django.contrib import admin
from django.utils.translation import ugettext as _, ugettext_lazy
from django.utils.encoding import force_unicode
from django.conf import settings as global_settings
from django.http import HttpResponseRedirect, Http404
from django.contrib.admin.util import unquote
from django.contrib.admin.sites import AlreadyRegistered
if global_settings.USE_I18N:
    from django.views.i18n import javascript_catalog
else:
    from django.views.i18n import null_javascript_catalog as javascript_catalog

from os.path import join

class PageAdmin(admin.ModelAdmin):
    """Page Admin class."""

    form = PageForm
    exclude = ['author', 'parent']
    # these mandatory fields are not versioned
    mandatory_placeholders = ('title', 'slug')
    general_fields = ['title', 'slug', 'status', 'target',
        'position', 'freeze_date']

    if settings.PAGE_USE_SITE_ID and not settings.PAGE_HIDE_SITES:
        general_fields.append('sites')
    insert_point = general_fields.index('status') + 1

    # Strange django behavior. If not provided, django will try to find
    # 'page' foreign key in all registered models
    inlines = []

    if settings.PAGE_TAGGING:
        general_fields.insert(insert_point, 'tags')

    # Add support for future dating and expiration based on settings.
    if settings.PAGE_SHOW_END_DATE:
        general_fields.insert(insert_point, 'publication_end_date')
    if settings.PAGE_SHOW_START_DATE:
        general_fields.insert(insert_point, 'publication_date')

    from pages.urlconf_registry import registry
    if(len(registry)):
        general_fields.append('delegate_to')
        insert_point = general_fields.index('status') + 1

    normal_fields = ['language']
    page_templates = settings.get_page_templates()
    if len(page_templates) > 0:
        normal_fields.append('template')
    normal_fields.append('redirect_to')
    normal_fields.append('redirect_to_url')
    fieldsets = (
        [_('General'), {
            'fields': general_fields,
            'classes': ('module-general',),
        }],
        (_('Options'), {
            'fields': normal_fields,
            'classes': ('module-options',),
        }),
    )

    actions = [export_pages_as_json]

    class Media:
        css = {
            'all': [join(settings.PAGES_MEDIA_URL, path) for path in (
                'css/rte.css',
                'css/pages.css'
            )]
        }
        js = [join(settings.PAGES_MEDIA_URL, path) for path in (
            'javascript/jquery.js',
            'javascript/jquery.rte.js',
            'javascript/jquery.query.js',
            'javascript/pages.js',
        )]

    def urls(self):
        from django.conf.urls.defaults import patterns, url, include

        # Admin-site-wide views.
        urlpatterns = patterns('',
            url(r'^$', self.list_pages, name='page-index'),
            url(r'^(?P<page_id>[0-9]+)/traduction/(?P<language_id>[-\w]+)/$',
                traduction, name='page-traduction'),
            url(r'^(?P<page_id>[0-9]+)/get-content/(?P<content_id>[0-9]+)/$',
                get_content, name='page-get-content'),
            url(r'^(?P<page_id>[0-9]+)/modify-content/(?P<content_type>[-\w]+)/(?P<language_id>[-\w]+)/$',
                modify_content, name='page-modify-content'),
            url(r'^(?P<page_id>[0-9]+)/delete-content/(?P<language_id>[-\w]+)/$',
                delete_content, name='page-delete-content'),
            url(r'^(?P<page_id>[0-9]+)/sub-menu/$',
                sub_menu, name='page-sub-menu'),
            url(r'^(?P<page_id>[0-9]+)/move-page/$',
                move_page, name='page-move-page'),
            url(r'^(?P<page_id>[0-9]+)/change-status/$',
                change_status, name='page-change-status'),
            url(r'^import-json/$',
                self.import_pages, name='import-pages-from-json'),
        )
        urlpatterns += super(PageAdmin, self).urls

        return urlpatterns

    urls = property(urls)

    def i18n_javascript(self, request):
        """Displays the i18n JavaScript that the Django admin
        requires.

        This takes into account the ``USE_I18N`` setting. If it's set to False, the
        generated JavaScript will be leaner and faster.
        """
        return javascript_catalog(request, packages='pages')

    def save_model(self, request, page, form, change):
        """Move the page in the tree if necessary and save every
        placeholder :class:`Content <pages.models.Content>`.
        """
        language = form.cleaned_data['language']
        target = form.data.get('target', None)
        position = form.data.get('position', None)
        page.save()

        # if True, we need to move the page
        if target and position:
            try:
                target = self.model.objects.get(pk=target)
            except self.model.DoesNotExist:
                pass
            else:
                target.invalidate()
                page.move_to(target, position)

        for name in self.mandatory_placeholders:
            data = form.cleaned_data[name]
            placeholder = PlaceholderNode(name)
            extra_data = placeholder.get_extra_data(form.data)
            placeholder.save(page, language, data, change,
                extra_data=extra_data)

        for placeholder in get_placeholders(page.get_template()):
            if(placeholder.name in form.cleaned_data and placeholder.name
                    not in self.mandatory_placeholders):
                data = form.cleaned_data[placeholder.name]
                extra_data = placeholder.get_extra_data(form.data)
                placeholder.save(page, language, data, change,
                    extra_data=extra_data)

        page.invalidate()

    def get_fieldsets(self, request, obj=None):
        """
        Add fieldsets of placeholders to the list of already
        existing fieldsets.
        """
        general_fields = list(self.general_fields)
        perms = PagePermission(request.user)

        # some ugly business to remove freeze_date
        # from the field list
        general_module = {
            'fields': list(self.general_fields),
            'classes': ('module-general',),
        }

        default_fieldsets = list(self.fieldsets)
        if not perms.check('freeze'):
            general_module['fields'].remove('freeze_date')
        if not perms.check('publish'):
            general_module['fields'].remove('status')

        default_fieldsets[0][1] = general_module

        placeholder_fieldsets = []
        template = get_template_from_request(request, obj)
        for placeholder in get_placeholders(template):
            if placeholder.name not in self.mandatory_placeholders:
                placeholder_fieldsets.append(placeholder.name)

        additional_fieldsets = []
        additional_fieldsets.append((_('Content'), {
            'fields': placeholder_fieldsets,
            'classes': ('module-content',),
        }))

        return default_fieldsets + additional_fieldsets

    def save_form(self, request, form, change):
        """Given a ModelForm return an unsaved instance. ``change`` is True if
        the object is being changed, and False if it's being added."""
        instance = super(PageAdmin, self).save_form(request, form, change)
        instance.template = form.cleaned_data['template']
        if not change:
            instance.author = request.user
        return instance

    def get_form(self, request, obj=None, **kwargs):
        """Get a :class:`Page <pages.admin.forms.PageForm>` for the
        :class:`Page <pages.models.Page>` and modify its fields depending on
        the request."""
        form = super(PageAdmin, self).get_form(request, obj, **kwargs)

        language = get_language_from_request(request)
        form.base_fields['language'].initial = language
        if obj:
            initial_slug = obj.slug(language=language, fallback=False)
            initial_title = obj.title(language=language, fallback=False)
            form.base_fields['slug'].initial = initial_slug
            form.base_fields['title'].initial = initial_title
            form.base_fields['slug'].label = _('Slug')

        template = get_template_from_request(request, obj)
        page_templates = settings.get_page_templates()
        if len(page_templates) > 0:
            template_choices = list(page_templates)
            template_choices.insert(0, (settings.PAGE_DEFAULT_TEMPLATE,
                    _('Default template')))
            form.base_fields['template'].choices = template_choices
            form.base_fields['template'].initial = force_unicode(template)

        for placeholder in get_placeholders(template):
            name = placeholder.name
            if obj:
                initial = placeholder.get_content(obj, language, name)
            else:
                initial = None
            form.base_fields[name] = placeholder.get_field(obj,
                language, initial=initial)

        return form

    def change_view(self, request, object_id, extra_context=None):
        """The ``change`` admin view for the
        :class:`Page <pages.models.Page>`."""
        language = get_language_from_request(request)
        extra_context = {
            'language': language,
            # don't see where it's used
            #'lang': current_lang,
            'page_languages': settings.PAGE_LANGUAGES,
        }
        try:
            int(object_id)
        except ValueError:
            raise Http404('The "%s" part of the location is invalid.'
                % str(object_id))
        try:
            obj = self.model.objects.get(pk=object_id)
        except self.model.DoesNotExist:
            # Don't raise Http404 just yet, because we haven't checked
            # permissions yet. We don't want an unauthenticated user to be able
            # to determine whether a given object exists.
            obj = None
        else:
            template = get_template_from_request(request, obj)
            extra_context['placeholders'] = get_placeholders(template)
            extra_context['traduction_languages'] = [l for l in
                settings.PAGE_LANGUAGES if Content.objects.get_content(obj,
                                    l[0], "title") and l[0] != language]
        extra_context['page'] = obj
        return super(PageAdmin, self).change_view(request, object_id,
                                                        extra_context)

    def add_view(self, request, form_url='', extra_context=None):
        """The ``add`` admin view for the :class:`Page <pages.models.Page>`."""
        extra_context = {
            'language': get_language_from_request(request),
            'page_languages': settings.PAGE_LANGUAGES,
        }
        template = get_template_from_request(request)
        #extra_context['placeholders'] = get_placeholders(template)
        return super(PageAdmin, self).add_view(request, form_url,
                                                            extra_context)

    def has_add_permission(self, request):
        """Return ``True`` if the current user has permission to add a new
        page."""
        lang = get_language_from_request(request)
        return PagePermission(request.user).check('add', lang=lang)

    def has_change_permission(self, request, obj=None):
        """Return ``True`` if the current user has permission
        to change the page."""
        lang = get_language_from_request(request)
        return PagePermission(request.user).check('change', page=obj,
            lang=lang, method=request.method)

    def has_delete_permission(self, request, obj=None):
        """Return ``True`` if the current user has permission on the page."""
        lang = get_language_from_request(request)
        return PagePermission(request.user).check('change', page=obj,
            lang=lang)

    def list_pages(self, request, template_name=None, extra_context=None):
        """List root pages"""
        if not self.admin_site.has_permission(request):
            return self.admin_site.login(request)
        language = get_language_from_request(request)

        query = request.POST.get('q', '').strip()

        if query:
            page_ids = list(set([c.page.pk for c in
                Content.objects.filter(body__icontains=query)]))
            pages = Page.objects.filter(pk__in=page_ids)
        else:
            pages = Page.objects.root()
        if settings.PAGE_HIDE_SITES:
            pages = pages.filter(sites=settings.SITE_ID)

        perms = PagePermission(request.user)
        context = {
            'can_publish': perms.check('publish'),
            'language': language,
            'name': _("page"),
            'pages': pages,
            'opts': self.model._meta,
            'q': query
        }

        context.update(extra_context or {})
        change_list = self.changelist_view(request, context)

        return change_list

    def import_pages(self, request):
        if not self.has_add_permission(request):
            return admin.site.login(request)

        return import_pages_from_json(request)

class PageAdminWithDefaultContent(PageAdmin):
    """
    Fill in values for content blocks from official language
    if creating a new translation
    """
    def get_form(self, request, obj=None, **kwargs):
        form = super(PageAdminWithDefaultContent, self
            ).get_form(request, obj, **kwargs)

        language = get_language_from_request(request)

        if global_settings.LANGUAGE_CODE == language:
            # this is the "official" language
            return form

        if Content.objects.filter(page=obj, language=language).count():
            return form

        # this is a new page, try to find some default content
        template = get_template_from_request(request, obj)
        for placeholder in get_placeholders(template):
            name = placeholder.name
            form.base_fields[name] = placeholder.get_field(obj, language,
                initial=Content.objects.get_content(obj,
                    global_settings.LANGUAGE_CODE, name))
        return form

for admin_class, model, options in get_connected():
    PageAdmin.inlines.append(make_inline_admin(admin_class, model, options))

try:
    admin.site.register(Page, PageAdmin)
except AlreadyRegistered:
    pass

class ContentAdmin(admin.ModelAdmin):
    list_display = ('__unicode__', 'type', 'language', 'page')
    list_filter = ('page',)
    search_fields = ('body',)

#admin.site.register(Content, ContentAdmin)

class AliasAdmin(admin.ModelAdmin):
    list_display = ('page', 'url',)
    list_editable = ('url', )

try:
    admin.site.register(PageAlias, AliasAdmin)
except AlreadyRegistered:
    pass

<commit_msg>Django 1.4 Fix: ModelAdmin.change_view method's arguments changed and extra_context wasn't being set correctly, which most-notably caused the Revisions list to go missing<commit_after># -*- coding: utf-8 -*-
"""Page Admin module."""
from pages import settings
from pages.models import Page, Content, PageAlias
from pages.http import get_language_from_request, get_template_from_request
from pages.utils import get_placeholders
from pages.templatetags.pages_tags import PlaceholderNode
from pages.admin.utils import get_connected, make_inline_admin
from pages.admin.forms import PageForm
from pages.admin.views import traduction, get_content, sub_menu
from pages.admin.views import list_pages_ajax
from pages.admin.views import change_status, modify_content, delete_content
from pages.admin.views import move_page
from pages.admin.actions import export_pages_as_json, import_pages_from_json
from pages.permissions import PagePermission
from pages.http import auto_render
import pages.widgets

from django.contrib import admin
from django.utils.translation import ugettext as _, ugettext_lazy
from django.utils.encoding import force_unicode
from django.conf import settings as global_settings
from django.http import HttpResponseRedirect, Http404
from django.contrib.admin.util import unquote
from django.contrib.admin.sites import AlreadyRegistered
if global_settings.USE_I18N:
    from django.views.i18n import javascript_catalog
else:
    from django.views.i18n import null_javascript_catalog as javascript_catalog

from os.path import join

class PageAdmin(admin.ModelAdmin):
    """Page Admin class."""

    form = PageForm
    exclude = ['author', 'parent']
    # these mandatory fields are not versioned
    mandatory_placeholders = ('title', 'slug')
    general_fields = ['title', 'slug', 'status', 'target',
        'position', 'freeze_date']

    if settings.PAGE_USE_SITE_ID and not settings.PAGE_HIDE_SITES:
        general_fields.append('sites')
    insert_point = general_fields.index('status') + 1

    # Strange django behavior. If not provided, django will try to find
    # 'page' foreign key in all registered models
    inlines = []

    if settings.PAGE_TAGGING:
        general_fields.insert(insert_point, 'tags')

    # Add support for future dating and expiration based on settings.
    if settings.PAGE_SHOW_END_DATE:
        general_fields.insert(insert_point, 'publication_end_date')
    if settings.PAGE_SHOW_START_DATE:
        general_fields.insert(insert_point, 'publication_date')

    from pages.urlconf_registry import registry
    if(len(registry)):
        general_fields.append('delegate_to')
        insert_point = general_fields.index('status') + 1

    normal_fields = ['language']
    page_templates = settings.get_page_templates()
    if len(page_templates) > 0:
        normal_fields.append('template')
    normal_fields.append('redirect_to')
    normal_fields.append('redirect_to_url')
    fieldsets = (
        [_('General'), {
            'fields': general_fields,
            'classes': ('module-general',),
        }],
        (_('Options'), {
            'fields': normal_fields,
            'classes': ('module-options',),
        }),
    )

    actions = [export_pages_as_json]

    class Media:
        css = {
            'all': [join(settings.PAGES_MEDIA_URL, path) for path in (
                'css/rte.css',
                'css/pages.css'
            )]
        }
        js = [join(settings.PAGES_MEDIA_URL, path) for path in (
            'javascript/jquery.js',
            'javascript/jquery.rte.js',
            'javascript/jquery.query.js',
            'javascript/pages.js',
        )]

    def urls(self):
        from django.conf.urls.defaults import patterns, url, include

        # Admin-site-wide views.
        urlpatterns = patterns('',
            url(r'^$', self.list_pages, name='page-index'),
            url(r'^(?P<page_id>[0-9]+)/traduction/(?P<language_id>[-\w]+)/$',
                traduction, name='page-traduction'),
            url(r'^(?P<page_id>[0-9]+)/get-content/(?P<content_id>[0-9]+)/$',
                get_content, name='page-get-content'),
            url(r'^(?P<page_id>[0-9]+)/modify-content/(?P<content_type>[-\w]+)/(?P<language_id>[-\w]+)/$',
                modify_content, name='page-modify-content'),
            url(r'^(?P<page_id>[0-9]+)/delete-content/(?P<language_id>[-\w]+)/$',
                delete_content, name='page-delete-content'),
            url(r'^(?P<page_id>[0-9]+)/sub-menu/$',
                sub_menu, name='page-sub-menu'),
            url(r'^(?P<page_id>[0-9]+)/move-page/$',
                move_page, name='page-move-page'),
            url(r'^(?P<page_id>[0-9]+)/change-status/$',
                change_status, name='page-change-status'),
            url(r'^import-json/$',
                self.import_pages, name='import-pages-from-json'),
        )
        urlpatterns += super(PageAdmin, self).urls

        return urlpatterns

    urls = property(urls)

    def i18n_javascript(self, request):
        """Displays the i18n JavaScript that the Django admin
        requires.

        This takes into account the ``USE_I18N`` setting. If it's set to False, the
        generated JavaScript will be leaner and faster.
        """
        return javascript_catalog(request, packages='pages')

    def save_model(self, request, page, form, change):
        """Move the page in the tree if necessary and save every
        placeholder :class:`Content <pages.models.Content>`.
        """
        language = form.cleaned_data['language']
        target = form.data.get('target', None)
        position = form.data.get('position', None)
        page.save()

        # if True, we need to move the page
        if target and position:
            try:
                target = self.model.objects.get(pk=target)
            except self.model.DoesNotExist:
                pass
            else:
                target.invalidate()
                page.move_to(target, position)

        for name in self.mandatory_placeholders:
            data = form.cleaned_data[name]
            placeholder = PlaceholderNode(name)
            extra_data = placeholder.get_extra_data(form.data)
            placeholder.save(page, language, data, change,
                extra_data=extra_data)

        for placeholder in get_placeholders(page.get_template()):
            if(placeholder.name in form.cleaned_data and placeholder.name
                    not in self.mandatory_placeholders):
                data = form.cleaned_data[placeholder.name]
                extra_data = placeholder.get_extra_data(form.data)
                placeholder.save(page, language, data, change,
                    extra_data=extra_data)

        page.invalidate()

    def get_fieldsets(self, request, obj=None):
        """
        Add fieldsets of placeholders to the list of already
        existing fieldsets.
        """
        general_fields = list(self.general_fields)
        perms = PagePermission(request.user)

        # some ugly business to remove freeze_date
        # from the field list
        general_module = {
            'fields': list(self.general_fields),
            'classes': ('module-general',),
        }

        default_fieldsets = list(self.fieldsets)
        if not perms.check('freeze'):
            general_module['fields'].remove('freeze_date')
        if not perms.check('publish'):
            general_module['fields'].remove('status')

        default_fieldsets[0][1] = general_module

        placeholder_fieldsets = []
        template = get_template_from_request(request, obj)
        for placeholder in get_placeholders(template):
            if placeholder.name not in self.mandatory_placeholders:
                placeholder_fieldsets.append(placeholder.name)

        additional_fieldsets = []
        additional_fieldsets.append((_('Content'), {
            'fields': placeholder_fieldsets,
            'classes': ('module-content',),
        }))

        return default_fieldsets + additional_fieldsets

    def save_form(self, request, form, change):
        """Given a ModelForm return an unsaved instance. ``change`` is True if
        the object is being changed, and False if it's being added."""
        instance = super(PageAdmin, self).save_form(request, form, change)
        instance.template = form.cleaned_data['template']
        if not change:
            instance.author = request.user
        return instance

    def get_form(self, request, obj=None, **kwargs):
        """Get a :class:`Page <pages.admin.forms.PageForm>` for the
        :class:`Page <pages.models.Page>` and modify its fields depending on
        the request."""
        form = super(PageAdmin, self).get_form(request, obj, **kwargs)

        language = get_language_from_request(request)
        form.base_fields['language'].initial = language
        if obj:
            initial_slug = obj.slug(language=language, fallback=False)
            initial_title = obj.title(language=language, fallback=False)
            form.base_fields['slug'].initial = initial_slug
            form.base_fields['title'].initial = initial_title
            form.base_fields['slug'].label = _('Slug')

        template = get_template_from_request(request, obj)
        page_templates = settings.get_page_templates()
        if len(page_templates) > 0:
            template_choices = list(page_templates)
            template_choices.insert(0, (settings.PAGE_DEFAULT_TEMPLATE,
                    _('Default template')))
            form.base_fields['template'].choices = template_choices
            form.base_fields['template'].initial = force_unicode(template)

        for placeholder in get_placeholders(template):
            name = placeholder.name
            if obj:
                initial = placeholder.get_content(obj, language, name)
            else:
                initial = None
            form.base_fields[name] = placeholder.get_field(obj,
                language, initial=initial)

        return form

    def change_view(self, request, object_id, form_url='', extra_context=None):
        """The ``change`` admin view for the
        :class:`Page <pages.models.Page>`."""
        language = get_language_from_request(request)
        extra_context = {
            'language': language,
            # don't see where it's used
            #'lang': current_lang,
            'page_languages': settings.PAGE_LANGUAGES,
        }
        try:
            int(object_id)
        except ValueError:
            raise Http404('The "%s" part of the location is invalid.'
                % str(object_id))
        try:
            obj = self.model.objects.get(pk=object_id)
        except self.model.DoesNotExist:
            # Don't raise Http404 just yet, because we haven't checked
            # permissions yet. We don't want an unauthenticated user to be able
            # to determine whether a given object exists.
            obj = None
        else:
            template = get_template_from_request(request, obj)
            extra_context['placeholders'] = get_placeholders(template)
            extra_context['traduction_languages'] = [l for l in
                settings.PAGE_LANGUAGES if Content.objects.get_content(obj,
                                    l[0], "title") and l[0] != language]
        extra_context['page'] = obj
        return super(PageAdmin, self).change_view(request, object_id, form_url=form_url, extra_context=extra_context)

    def add_view(self, request, form_url='', extra_context=None):
        """The ``add`` admin view for the :class:`Page <pages.models.Page>`."""
        extra_context = {
            'language': get_language_from_request(request),
            'page_languages': settings.PAGE_LANGUAGES,
        }
        template = get_template_from_request(request)
        #extra_context['placeholders'] = get_placeholders(template)
        return super(PageAdmin, self).add_view(request, form_url,
                                                            extra_context)

    def has_add_permission(self, request):
        """Return ``True`` if the current user has permission to add a new
        page."""
        lang = get_language_from_request(request)
        return PagePermission(request.user).check('add', lang=lang)

    def has_change_permission(self, request, obj=None):
        """Return ``True`` if the current user has permission
        to change the page."""
        lang = get_language_from_request(request)
        return PagePermission(request.user).check('change', page=obj,
            lang=lang, method=request.method)

    def has_delete_permission(self, request, obj=None):
        """Return ``True`` if the current user has permission on the page."""
        lang = get_language_from_request(request)
        return PagePermission(request.user).check('change', page=obj,
            lang=lang)

    def list_pages(self, request, template_name=None, extra_context=None):
        """List root pages"""
        if not self.admin_site.has_permission(request):
            return self.admin_site.login(request)
        language = get_language_from_request(request)

        query = request.POST.get('q', '').strip()

        if query:
            page_ids = list(set([c.page.pk for c in
                Content.objects.filter(body__icontains=query)]))
            pages = Page.objects.filter(pk__in=page_ids)
        else:
            pages = Page.objects.root()
        if settings.PAGE_HIDE_SITES:
            pages = pages.filter(sites=settings.SITE_ID)

        perms = PagePermission(request.user)
        context = {
            'can_publish': perms.check('publish'),
            'language': language,
            'name': _("page"),
            'pages': pages,
            'opts': self.model._meta,
            'q': query
        }

        context.update(extra_context or {})
        change_list = self.changelist_view(request, context)

        return change_list

    def import_pages(self, request):
        if not self.has_add_permission(request):
            return admin.site.login(request)

        return import_pages_from_json(request)

class PageAdminWithDefaultContent(PageAdmin):
    """
    Fill in values for content blocks from official language
    if creating a new translation
    """
    def get_form(self, request, obj=None, **kwargs):
        form = super(PageAdminWithDefaultContent, self
            ).get_form(request, obj, **kwargs)

        language = get_language_from_request(request)

        if global_settings.LANGUAGE_CODE == language:
            # this is the "official" language
            return form

        if Content.objects.filter(page=obj, language=language).count():
            return form

        # this is a new page, try to find some default content
        template = get_template_from_request(request, obj)
        for placeholder in get_placeholders(template):
            name = placeholder.name
            form.base_fields[name] = placeholder.get_field(obj, language,
                initial=Content.objects.get_content(obj,
                    global_settings.LANGUAGE_CODE, name))
        return form

for admin_class, model, options in get_connected():
    PageAdmin.inlines.append(make_inline_admin(admin_class, model, options))

try:
    admin.site.register(Page, PageAdmin)
except AlreadyRegistered:
    pass

class ContentAdmin(admin.ModelAdmin):
    list_display = ('__unicode__', 'type', 'language', 'page')
    list_filter = ('page',)
    search_fields = ('body',)

#admin.site.register(Content, ContentAdmin)

class AliasAdmin(admin.ModelAdmin):
    list_display = ('page', 'url',)
    list_editable = ('url', )

try:
    admin.site.register(PageAlias, AliasAdmin)
except AlreadyRegistered:
    pass

<|endoftext|>


<commit_before>#!/usr/bin/env python3
'''syspower: A platform agnostic library for power state management.

   For any given operation, we first determine the platform type, and
   then try to use some extra stuff to narrow down what specific methods
   might work on this system for the requested operation (mostly needed
   on Linux), and then finally try those methods in a priority order.

   CONSOLE_AUTH_TYPES is a list of password-less console based prievelge
   escalation methods we will iterate through when trying to performa
   an operation.

   Copyright (c) 2016, Austin S. Hemmelgarn
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
   2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY OF SUCH DAMAGE.'''

import sys
import os
import subprocess

CONSOLE_AUTH_TYPES = {
    'sudo -n',
    'doas -n',
    'pkexec'
}

class UnsupportedOperation(Exception):
    '''Raised when a particular operation is not supported on the current platform.

       This is essentially the same as returning NotImplemented, we just
       use a different name to be more clear.'''

class NoWorkingMethod(Exception):
    '''Raised when a method for the operation can't be found for the platform.

       In essence, if you get this, we technically support the platform,
       but none of the things we try to perform the requested operation
       on that platform worked.'''

def _try_commands(commands):
    '''Tries each command in sequence, returning True if one succeeded and False otherwise.'''
    for command in commands:
        try:
            status = os.system(command)
            if status == 0:
                return True
        except OSError:
            pass
    return False

def _get_shutdown_poweroff_opts():
    '''Figure out what to pass to /sbin/shutdwon to power-off

       This is needed because options are inconsistent between modern
       Linux, old Linux, SVR4 derived systems, BSD derived systems,
       and Solaris derived systems.'''
    if os.system == 'posix' and sys.platform.startswith('darwin'):
        # Assume we're on OS X, which wants no arguments for poweroff
        return ''
    try:
        shutdownhelp = subprocess.check_output(['shutdown', '--help'], shell=True)
    except subprocess.CalledProcessError:
        # Either shutdown doesn't support --help (which means it's
        # ancient), or doesn't exist.  In either case, assume old
        # Linux/SVR4 options, which should work on most systems (at
        # least to bring the system down.
        return '-h'
    if shutdownhelp.find(b'-p') != -1:
        # This covers BSD style shutdown.
        return '-p'
    elif shutdownhelp.find(b'-P') != -1:
        # This covers older Linux style shutdown.
        return '-hP'
    else:
        # This covers most other stuff.
        return ''

def _generic_unix_shutdown():
    '''Internal function that tries methods that are generic to most UNIX systems.

       First, we check if we're EUID 0, and if so just try calling
       shutdown directly (followed by poweroff and halt if they exist
       and shutdown fails).

       Then we try to call them in the same order using the various
       methods in CONSOLE_AUTH_TYPES.

       Third we try directly calling shutdown, poweroff, telinit 0,
       and halt in that order (some of thewse will actually work if
       we're not root).'''
    cmdlist = [
        'shutdown ' + _get_shutdown_poweroff_opts() + ' now',
        'poweroff',
        'telinit 0',
        'halt'
    ]
    if os.geteuid() == 0:
        if _try_commands(cmdlist):
            return True
    for prefix in CONSOLE_AUTH_TYPES:
        tmpcmdlist = list()
        for i in range(0, len(cmdlist)):
            tmpcmdlist[i] = prefix + cmdlist[i]
        if _try_commands(tmpcmdlist):
            return True
    if _try_commands(cmdlist):
        return True
    return False

def _generic_unix_reboot():
    '''Internal function that tries methods that are generic to most UNIX systems.

       Similar arrangement to _generic_unix_shutdown, just with
       shutdown -r, reboot, and telinit 6.'''
    cmdlist = [
        'shutdown -r now',
        'reboot',
        'telinit 6'
    ]
    if os.geteuid() == 0:
        if _try_commands(cmdlist):
            return True
    for prefix in CONSOLE_AUTH_TYPES:
        tmpcmdlist = list()
        for i in range(0, len(cmdlist)):
            tmpcmdlist[i] = prefix + cmdlist[i]
        if _try_commands(tmpcmdlist):
            return True
    if _try_commands(cmdlist):
        return True
    return False

def shutdown():
    '''Initiate a system shutdown.

       In most cases, this will either never return (if the shutdown
       is immediate, or the method blocks until the shutdown occurs,
       then this wont' return) or raise an error (if we can't find a
       method that works or the platform is unsupported).  In the event
       that we do return, we'll return true if we think things worked
       (which may not mean that they actually did work).'''
    if os.system == 'posix':
        if sys.platform.startswith('linux'):
            if _generic_unix_shutdown():
                return True
            raise NoWorkingMethod
        elif sys.platform.startswith('darwin'):
            if _generic_unix_shutdown():
                return True
            raise NoWorkingMethod
        elif sys.platform.startswith('SunOS') or sys.platform.startswith('solaris'):
            # Newer versions of Solaris have a wierd shutdown command
            # that behaves like telinit with confirmation, try that first
            # before trying the generic UNIX shutdown stuff.
            try:
                status = os.system('shutdown -y -i 5 5')
                if status == 0:
                    return True
            except OSError:
                pass
            if _generic_unix_shutdown():
                return True
            raise NoWorkingMethod
        if _generic_unix_shutdown():
            return True
        raise NoWorkingMethod
    elif os.system == 'nt':
        try:
            status = os.system('shutdown /s')
            if status == 0:
                return True
        except OSError:
            pass
        raise NoWorkingMethod
    else:
        raise UnsupportedOperation

def reboot():
    '''Initiate a system reboot.

       In most cases, this will either never return (if the shutdown
       is immediate, or the method blocks until the shutdown occurs,
       then this wont' return) or raise an error (if we can't find a
       method that works or the platform is unsupported).  In the event
       that we do return, we'll return true if we think things worked
       (which may not mean that they actually did work).'''
    if os.system == 'posix':
        if sys.platform.startswith('linux'):
            if _generic_unix_reboot():
                return True
            raise NoWorkingMethod
        elif sys.platform.startswith('darwin'):
            if _generic_unix_reboot():
                return True
            raise NoWorkingMethod
        elif sys.platform.startswith('SunOS') or sys.platform.startswith('solaris'):
            # Newer versions of Solaris have a wierd shutdown command
            # that behaves like telinit with confirmation, try that first
            # before trying the generic UNIX reboot stuff.
            try:
                status = os.system('shutdown -y -i 6 6')
            except OSError:
                pass
            if status == 0:
                return True
            if _generic_unix_reboot():
                return True
            raise NoWorkingMethod
        if _generic_unix_reboot():
            return True
        raise NoWorkingMethod
    elif os.system == 'nt':
        try:
            status = os.system('shutdown /r')
            if status == 0:
                return True
        except OSError:
            pass
        raise NoWorkingMethod
    else:
        raise UnsupportedOperation

def suspend():
    '''Suspend to RAM.

       This is equivalent to an ACPI S3 state on most systems, but may
       be different depending on the platform.

       Depending on the platform and method, this may return before the
       system has actually suspended to RAM, or it may not return until
       after the system next wakes up.  In either case, if there was no
       error, it will return True.'''
    if os.system == 'posix':
        if sys.platform.startswith('linux'):
            raise UnsupportedOperation
        elif sys.platform.startswith('darwin'):
            raise UnsupportedOperation
        else:
            raise UnsupportedOperation
    elif os.system == 'nt':
        raise UnsupportedOperation
    elif os.system == 'java':
        raise UnsupportedOperation
    else:
        raise UnsupportedOperation

def hibernate():
    '''Hibernate/Suspend to disk.

       This is an OS mediated operation, not a firmware mediated one.'''
    if os.system == 'posix':
        if sys.platform.startswith('linux'):
            raise UnsupportedOperation
        elif sys.platform.startswith('darwin'):
            raise UnsupportedOperation
        else:
            raise UnsupportedOperation
    elif os.system == 'nt':
        raise UnsupportedOperation
    elif os.system == 'java':
        raise UnsupportedOperation
    else:
        raise UnsupportedOperation
<commit_msg>Multiple fixes and minor updates:<commit_after>#!/usr/bin/env python3
'''syspower: A platform agnostic library for power state management.

   For any given operation, we first determine the platform type, and
   then try to use some extra stuff to narrow down what specific methods
   might work on this system for the requested operation (mostly needed
   on Linux), and then finally try those methods in a priority order.

   CONSOLE_AUTH_TYPES is a list of password-less console based prievelge
   escalation methods we will iterate through when trying to performa
   an operation.

   Copyright (c) 2016, Austin S. Hemmelgarn
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
   2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY OF SUCH DAMAGE.'''

import sys
import os
import subprocess

CONSOLE_AUTH_TYPES = {
    'sudo -n',
    'doas -n',
    'pkexec'
}

class UnsupportedOperation(Exception):
    '''Raised when a particular operation is not supported on the current platform.

       This is essentially the same as returning NotImplemented, we just
       use a different name to be more clear.'''

class NoWorkingMethod(Exception):
    '''Raised when a method for the operation can't be found for the platform.

       In essence, if you get this, we technically support the platform,
       but none of the things we try to perform the requested operation
       on that platform worked.'''

def _try_commands(commands):
    '''Tries each command in sequence, returning True if one succeeded and False otherwise.'''
    for command in commands:
        try:
            status = subprocess.check_call(command, shell=True)
            if status == 0:
                return True
        except subprocess.SubprocessError:
            pass
    return False

def _get_shutdown_poweroff_opts():
    '''Figure out what to pass to /sbin/shutdwon to power-off

       This is needed because options are inconsistent between modern
       Linux, old Linux, SVR4 derived systems, BSD derived systems,
       and Solaris derived systems.'''
    if os.name == 'posix' and sys.platform.startswith('darwin'):
        # Assume we're on OS X, which wants no arguments for poweroff
        return ''
    try:
        shutdownhelp = subprocess.check_output(['shutdown', '--help'], shell=True)
    except subprocess.SubprocessError:
        # Either shutdown doesn't support --help (which means it's
        # ancient), or doesn't exist.  In either case, assume old
        # Linux/SVR4 options, which should work on most systems (at
        # least to bring the system down.
        return '-h'
    if shutdownhelp.find(b'-p') != -1:
        # This covers BSD style shutdown.
        return '-p'
    elif shutdownhelp.find(b'-P') != -1:
        # This covers older Linux style shutdown.
        return '-hP'
    else:
        # This covers most other stuff.
        return ''

def _generic_unix_shutdown():
    '''Internal function that tries methods that are generic to most UNIX systems.

       First, we check if we're EUID 0, and if so just try calling
       shutdown directly (followed by poweroff and halt if they exist
       and shutdown fails).

       Then we try to call them in the same order using the various
       methods in CONSOLE_AUTH_TYPES.

       Third we try directly calling shutdown, poweroff, telinit 0,
       and halt in that order (some of thewse will actually work if
       we're not root).'''
    cmdlist = [
        ['shutdown', _get_shutdown_poweroff_opts(), 'now'],
        ['poweroff'],
        ['teliniti', '0'],
        ['halt']
    ]
    if os.geteuid() == 0:
        if _try_commands(cmdlist):
            return True
    for prefix in CONSOLE_AUTH_TYPES:
        tmpcmdlist = list()
        for i in range(0, len(cmdlist)):
            tmpcmdlist[i] = prefix + cmdlist[i]
        if _try_commands(tmpcmdlist):
            return True
    if _try_commands(cmdlist):
        return True
    return False

def _generic_unix_reboot():
    '''Internal function that tries methods that are generic to most UNIX systems.

       Similar arrangement to _generic_unix_shutdown, just with
       shutdown -r, reboot, and telinit 6.'''
    cmdlist = [
        ['shutdown', '-r', 'now'],
        ['reboot'],
        ['telinit', '6']
    ]
    if os.geteuid() == 0:
        if _try_commands(cmdlist):
            return True
    for prefix in CONSOLE_AUTH_TYPES:
        tmpcmdlist = list()
        for i in range(0, len(cmdlist)):
            tmpcmdlist[i] = prefix + cmdlist[i]
        if _try_commands(tmpcmdlist):
            return True
    if _try_commands(cmdlist):
        return True
    return False

def shutdown():
    '''Initiate a system shutdown.

       In most cases, this will either never return (if the shutdown
       is immediate, or the method blocks until the shutdown occurs,
       then this wont' return) or raise an error (if we can't find a
       method that works or the platform is unsupported).  In the event
       that we do return, we'll return true if we think things worked
       (which may not mean that they actually did work).'''
    if os.name == 'posix':
        if sys.platform.startswith('linux'):
            if _generic_unix_shutdown():
                return True
            raise NoWorkingMethod
        elif sys.platform.startswith('darwin'):
            if _generic_unix_shutdown():
                return True
            raise NoWorkingMethod
        elif sys.platform.startswith('SunOS') or sys.platform.startswith('solaris'):
            # Newer versions of Solaris have a wierd shutdown command
            # that behaves like telinit with confirmation, try that first
            # before trying the generic UNIX shutdown stuff.
            try:
                status = subprocess.check_call(['shutdown', '-y', '-i 5', '5'], shell=True)
                if status == 0:
                    return True
            except subprocess.SubprocessError:
                pass
            if _generic_unix_shutdown():
                return True
            raise NoWorkingMethod
        if _generic_unix_shutdown():
            return True
        raise NoWorkingMethod
    elif os.name == 'nt':
        try:
            status = subprocess.check_call(['shutdown', '/s'], shell=True)
            if status == 0:
                return True
        except subprocess.SubprocessError:
            pass
        raise NoWorkingMethod
    else:
        raise UnsupportedOperation

def reboot():
    '''Initiate a system reboot.

       In most cases, this will either never return (if the shutdown
       is immediate, or the method blocks until the shutdown occurs,
       then this wont' return) or raise an error (if we can't find a
       method that works or the platform is unsupported).  In the event
       that we do return, we'll return true if we think things worked
       (which may not mean that they actually did work).'''
    if os.name == 'posix':
        if sys.platform.startswith('linux'):
            if _generic_unix_reboot():
                return True
            raise NoWorkingMethod
        elif sys.platform.startswith('darwin'):
            if _generic_unix_reboot():
                return True
            raise NoWorkingMethod
        elif sys.platform.startswith('SunOS') or sys.platform.startswith('solaris'):
            # Newer versions of Solaris have a wierd shutdown command
            # that behaves like telinit with confirmation, try that first
            # before trying the generic UNIX reboot stuff.
            try:
                status = subprocess.check_call(['shutdown', '-y', '-i 6', '6'], shell=True)
            except subprocess.SubprocessError:
                pass
            if status == 0:
                return True
            if _generic_unix_reboot():
                return True
            raise NoWorkingMethod
        if _generic_unix_reboot():
            return True
        raise NoWorkingMethod
    elif os.name == 'nt':
        try:
            status = subprocess.check_call(['shutdown', '/r'], shell=True)
            if status == 0:
                return True
        except subprocess.SubprocessError:
            pass
        raise NoWorkingMethod
    else:
        raise UnsupportedOperation

def suspend():
    '''Suspend to RAM.

       This is equivalent to an ACPI S3 state on most systems, but may
       be different depending on the platform.

       Depending on the platform and method, this may return before the
       system has actually suspended to RAM, or it may not return until
       after the system next wakes up.  In either case, if there was no
       error, it will return True.'''
    if os.name == 'posix':
        if sys.platform.startswith('linux'):
            raise UnsupportedOperation
        elif sys.platform.startswith('darwin'):
            raise UnsupportedOperation
        else:
            raise UnsupportedOperation
    elif os.name == 'nt':
        raise UnsupportedOperation
    else:
        raise UnsupportedOperation

def hibernate():
    '''Hibernate/Suspend to disk.

       This is an OS mediated operation, not a firmware mediated one.'''
    if os.name == 'posix':
        if sys.platform.startswith('linux'):
            raise UnsupportedOperation
        elif sys.platform.startswith('darwin'):
            raise UnsupportedOperation
        else:
            raise UnsupportedOperation
    elif os.name == 'nt':
        raise UnsupportedOperation
    else:
        raise UnsupportedOperation
<|endoftext|>


<commit_before>import logging
from contextlib import contextmanager

from pajbot.managers.db import DBManager
from pajbot.models.user import User
from pajbot.models.user import UserCombined
from pajbot.models.user import UserSQLCache
from pajbot.utils import time_method

log = logging.getLogger(__name__)

class UserManager:
    data = {}
    _instance = None

    def __init__(self):
        UserSQLCache.init()
        UserManager._instance = self

    @staticmethod
    def get():
        return UserManager._instance

    def save(self, user):
        """ Saves all data for a user.
        This means cached data (like his debts) and SQL """
        self.data[user.username] = user.save()

    @staticmethod
    def get_static(username, db_session=None, user_model=None, redis=None):
        return UserCombined(username, db_session=db_session, user_model=user_model, redis=redis)

    def get_user(self, username, db_session=None, user_model=None, redis=None):
        """ Return to call UserManager.save(user.username) an the user object manually when done with if. """
        user = UserCombined(username, db_session=db_session, user_model=user_model, redis=redis)
        user.load(**self.data.get(username, {}))
        return user

    @contextmanager
    def get_user_context(self, username):
        try:
            user = UserCombined(username)
            user.load(**self.data.get(username, {}))

            yield user
        except:
            log.exception("Uncaught exception in UserManager::get_user({})".format(username))
        finally:
            self.save(user)

    def __getitem__(self, username):
        return self.get_user(username)

    @contextmanager
    def find_context(self, username, db_session=None):
        try:
            user = self.find(username, db_session=db_session)
            yield user
        except:
            log.exception("Uncaught exception in UserManager::find_context({})".format(username))
        finally:
            if user:
                self.save(user)

    @staticmethod
    def find_static(username, db_session=None):
        """
        Attempts to find the user with the given username.

        Arguments:
        username - Username of the user we're trying to find. Case-insensitive.

        Returns a user object if the user already existed, otherwise return None
        """

        # from pajbot.utils import print_traceback
        # print_traceback()

        # log.debug('UserManager::find({})'.format(username))

        # Return None if the username is an empty string!
        if username == "":
            return None

        # Replace any occurances of @ in the username
        # This helps non-bttv-users who tab-complete usernames
        username = username.replace("@", "")

        # This will be used when we access the cache dictionary
        username_lower = username.lower()

        # Check for the username in the database
        user = UserManager.get_static(username_lower, db_session=db_session)
        if user.new:
            return None
        return user

    def find(self, username, db_session=None):
        """
        Attempts to find the user with the given username.

        Arguments:
        username - Username of the user we're trying to find. Case-insensitive.

        Returns a user object if the user already existed, otherwise return None
        """

        # from pajbot.utils import print_traceback
        # print_traceback()

        # log.debug('UserManager::find({})'.format(username))

        # Return None if the username is an empty string!
        if username == "":
            return None

        # Replace any occurances of @ in the username
        # This helps non-bttv-users who tab-complete usernames
        username = username.replace("@", "")

        # This will be used when we access the cache dictionary
        username_lower = username.lower()

        # Check for the username in the database
        user = self.get_user(username_lower, db_session=db_session)
        if user.new:
            return None
        return user

    @time_method
    def reset_subs(self):
        """ Returns how many subs were reset """
        with DBManager.create_session_scope() as db_session:
            return (
                db_session.query(User)
                .filter_by(subscriber=True)
                .update({User.subscriber: False}, synchronize_session=False)
            )

    @time_method
    def update_subs(self, subs):
        """
        subs is a list of usernames
        """

        with DBManager.create_session_scope() as db_session:
            subs = set(subs)
            for user in db_session.query(User).filter(User.username.in_(subs)):
                try:
                    subs.remove(user.username)
                except:
                    pass

                user.subscriber = True

            for username in subs:
                # New user!
                user = User(username=username)
                user.subscriber = True

                db_session.add(user)

    @staticmethod
    def bulk_load_user_models(usernames, db_session):
        users = db_session.query(User).filter(User.username.in_(usernames))
        return {user.username: user for user in users}
<commit_msg>seems like db_session.add just isn't needed (and crashes sometimes)<commit_after>import logging
from contextlib import contextmanager

from pajbot.managers.db import DBManager
from pajbot.models.user import User
from pajbot.models.user import UserCombined
from pajbot.models.user import UserSQLCache
from pajbot.utils import time_method

log = logging.getLogger(__name__)

class UserManager:
    data = {}
    _instance = None

    def __init__(self):
        UserSQLCache.init()
        UserManager._instance = self

    @staticmethod
    def get():
        return UserManager._instance

    def save(self, user):
        """ Saves all data for a user.
        This means cached data (like his debts) and SQL """
        self.data[user.username] = user.save()

    @staticmethod
    def get_static(username, db_session=None, user_model=None, redis=None):
        return UserCombined(username, db_session=db_session, user_model=user_model, redis=redis)

    def get_user(self, username, db_session=None, user_model=None, redis=None):
        """ Return to call UserManager.save(user.username) an the user object manually when done with if. """
        user = UserCombined(username, db_session=db_session, user_model=user_model, redis=redis)
        user.load(**self.data.get(username, {}))
        return user

    @contextmanager
    def get_user_context(self, username):
        try:
            user = UserCombined(username)
            user.load(**self.data.get(username, {}))

            yield user
        except:
            log.exception("Uncaught exception in UserManager::get_user({})".format(username))
        finally:
            self.save(user)

    def __getitem__(self, username):
        return self.get_user(username)

    @contextmanager
    def find_context(self, username, db_session=None):
        try:
            user = self.find(username, db_session=db_session)
            yield user
        except:
            log.exception("Uncaught exception in UserManager::find_context({})".format(username))
        finally:
            if user:
                self.save(user)

    @staticmethod
    def find_static(username, db_session=None):
        """
        Attempts to find the user with the given username.

        Arguments:
        username - Username of the user we're trying to find. Case-insensitive.

        Returns a user object if the user already existed, otherwise return None
        """

        # from pajbot.utils import print_traceback
        # print_traceback()

        # log.debug('UserManager::find({})'.format(username))

        # Return None if the username is an empty string!
        if username == "":
            return None

        # Replace any occurances of @ in the username
        # This helps non-bttv-users who tab-complete usernames
        username = username.replace("@", "")

        # This will be used when we access the cache dictionary
        username_lower = username.lower()

        # Check for the username in the database
        user = UserManager.get_static(username_lower, db_session=db_session)
        if user.new:
            return None
        return user

    def find(self, username, db_session=None):
        """
        Attempts to find the user with the given username.

        Arguments:
        username - Username of the user we're trying to find. Case-insensitive.

        Returns a user object if the user already existed, otherwise return None
        """

        # from pajbot.utils import print_traceback
        # print_traceback()

        # log.debug('UserManager::find({})'.format(username))

        # Return None if the username is an empty string!
        if username == "":
            return None

        # Replace any occurances of @ in the username
        # This helps non-bttv-users who tab-complete usernames
        username = username.replace("@", "")

        # This will be used when we access the cache dictionary
        username_lower = username.lower()

        # Check for the username in the database
        user = self.get_user(username_lower, db_session=db_session)
        if user.new:
            return None
        return user

    @time_method
    def reset_subs(self):
        """ Returns how many subs were reset """
        with DBManager.create_session_scope() as db_session:
            return (
                db_session.query(User)
                .filter_by(subscriber=True)
                .update({User.subscriber: False}, synchronize_session=False)
            )

    @time_method
    def update_subs(self, subs):
        """
        subs is a list of usernames
        """

        with DBManager.create_session_scope() as db_session:
            subs = set(subs)
            for user in db_session.query(User).filter(User.username.in_(subs)):
                try:
                    subs.remove(user.username)
                except:
                    pass

                user.subscriber = True

            for username in subs:
                # New user!
                user = User(username=username)
                user.subscriber = True

    @staticmethod
    def bulk_load_user_models(usernames, db_session):
        users = db_session.query(User).filter(User.username.in_(usernames))
        return {user.username: user for user in users}
<|endoftext|>


<commit_before>import imhdsk
import cpsk
from brutal.core.plugin import match, cmd, threaded
from brutal.core.utils import split_args_by
import codecs
import datetime
import sys
reload(sys)
sys.setdefaultencoding("utf-8")

def rootify(word):
    """Return probable root of the word."""

    if len(word) <= 5:
        return word

    w = word[::-1]
    vowels = ['a', 'e', 'i', 'o', 'u', 'y']
    for x in range(len(word)):
        if w[x] in vowels and x != 0:
            return word[:-(x + 1)]

@threaded
@cmd
def mhd(event):
    """Get the next BA MHD from A to B by running !mhd A B"""

    args = event.args

    if len(args) < 2:
        return

    args = list(args)

    if '-' in args:
        args = split_args_by(args, '-')

    f = args[0]
    t = args[1]

    if f == t:
        return "Not in this universe."

    time = ''
    date = ''
    if len(args) >= 3:
        time = args[2]
    if len(args) >= 4:
        date = args[3]

    r = imhdsk.routes(f, t, time=time, date=date)
    if len(r) == 0:
        return

    out = r[0].__repr__()
    out = unicode(out.strip(codecs.BOM_UTF8), 'utf-8')
    return out.encode('utf-8')

TRAVEL_REGEX = r'(?:mhd|bus|vlak|spoj)\s(?:z|zo)\s([A-Za-z\s]+)' \
    '\s(?:na|do)\s([A-Za-z\s]+)([\d]+:[\d]+)?(\s[\d\.]+)?'

@threaded
@match(regex=TRAVEL_REGEX)
def line_match(event, f, t, time=None, date=None, *args):
    """Search for mhd in BA or bus/train lines in Slovakia

    Examples:
        bus z mlyny na hlst
        vlak z BA do TO
        bus z BA do LM 18:00 20.12.2014
        spoj zo Zochova no mlyny
    """
    msg = event.meta['body']

    if f == t:
        return "Not in this universe."

    time = '' if time is None else time
    date = '' if date is None else date

    if ("zajtra" in msg or "pozajtra" in msg) and date is not '':
        if "pozajtra" in msg:
            delta = 2
        elif "zajtra" in msg:
            delta = 1
        date = (datetime.date.today() + datetime.timedelta(days=delta)) \
            .strftime("%d.%m.%Y")

    vehicle = "vlakbus"
    if "bus" in msg:
        vehicle = "bus"
    elif "vlak" in msg:
        vehicle = "vlak"

    r = cpsk.get_routes(f, t, vehicle=vehicle, time=time, date=date)
    if not len(r):
        f = imhdsk.clear_stop(imhdsk.suggest(
                              rootify(f.split(' ')[0]))[0]['name'])
        t = imhdsk.clear_stop(imhdsk.suggest(
                              rootify(t.split(' ')[0]))[0]['name'])

        r = imhdsk.routes(f, t, time=time, date=date)

    out = r[0].__repr__() if len(r) else "Nothing found"
    out = unicode(out.strip(codecs.BOM_UTF8), 'utf-8')
    return out.encode('utf-8')

def get_line(event, vehicle):
    """Searches for bus/train based on given vehicle argument"""
    args = event.args

    if len(args) < 2:
        return

    if '-' in args:
        args = split_args_by(args, '-')

    dep = args[0]
    dest = args[1]

    time = args[2] if len(args) > 2 else ''
    date = args[3] if len(args) > 3 else ''

    if dep == dest:
        return "You joker"

    r = cpsk.get_routes(dep, dest, vehicle=vehicle, time=time, date=date)
    return r[0].__repr__() if len(r) else "Nothing found"

@threaded
@cmd
def bus(event):
    """Search for next bus line from A to B

    Examples:
        !bus BA TO
        !bus Kosice - Bratislava - 19:00 - 20.12.2014
    """

    return get_line(event, 'bus')

@threaded
@cmd
def vlak(event):
    """Search for next train line from A to B

    Examples:
        !vlak Kosice Bratislava
        !vlak Kosice - Bratislava - 19:00 - 20.12.2014
    """
    return get_line(event, 'vlak')

@threaded
@cmd
def spoj(event):
    """Search for next means of transportation from A to B

    Examples:
        !spoj Kosice Bratislava
        !spoj Kosice - Bratislava - 19:00 - 24.12.2014
    """
    return get_line(event, 'vlakbus')
<commit_msg>travel: added option to search for next line<commit_after>import imhdsk
import cpsk
from brutal.core.plugin import match, cmd, threaded
from brutal.core.utils import split_args_by
import codecs
import datetime
import sys
reload(sys)
sys.setdefaultencoding("utf-8")

# 'nick' : ['dep', 'dest', 'time', 'date']
searched = {}

def send_output(nick, dep, dest, date, result=None):
    """Sends output"""
    out = 'Nothing found'

    if date == '':
        date = datetime.datetime.today().strftime('%d.%m.%Y')

    if len(result) >= 1:
        out = result[0].__repr__()
        obj = result[0]

        if hasattr(obj, 'lines') and len(obj.lines) >= 1:
            time = obj.lines[0].departure
        elif hasattr(result[0], 'drives') and len(obj.drives) >= 1:
            time = result[0].drives[0].begin_time
        searched[nick] = [dep, dest, time, date]

    out = unicode(out.strip(codecs.BOM_UTF8), 'utf-8')
    return out.encode('utf-8')

def searched_incrementer(nick):
    """Adds 1 minute to previous search departure"""
    dep, dest, time, date = searched[nick]

    dateobj = datetime.datetime.strptime('{0}-{1}'.format(time,
                                                          date),
                                         '%H:%M-%d.%m.%Y')
    dateobj += datetime.timedelta(seconds=60)
    date = dateobj.strftime('%d.%m.%Y')
    time = dateobj.strftime('%H:%M')

    searched[nick] = [dep, dest, time, date]
    return searched[nick]

def rootify(word):
    """Return probable root of the word."""

    if len(word) <= 5:
        return word

    w = word[::-1]
    vowels = ['a', 'e', 'i', 'o', 'u', 'y']
    for x in range(len(word)):
        if w[x] in vowels and x != 0:
            return word[:-(x + 1)]

@threaded
@cmd
def mhd(event):
    """Get the next BA MHD from A to B by running !mhd A B"""

    args = event.args

    if len(args) >= 1 and args[0] == 'next':
        if not event.meta['nick'] in searched:
            return 'No next line'
        args = searched_incrementer(event.meta['nick'])

    if len(args) < 2:
        return 'Not enough arguments specified. See !help mhd for usage'

    args = list(args)

    if '-' in args:
        args = split_args_by(args, '-')

    f = args[0]
    t = args[1]

    if f == t:
        return 'Not in this universe.'

    time = ''
    date = ''
    if len(args) >= 3:
        time = args[2]
    if len(args) >= 4:
        date = args[3]

    r = imhdsk.routes(f, t, time=time, date=date)
    if len(r) == 0:
        return

    return send_output(event.meta['nick'], f, t, date, result=r)

TRAVEL_REGEX = r'(?:mhd|bus|vlak|spoj)\s(?:z|zo)\s([A-Za-z\s]+)' \
    '\s(?:na|do)\s([A-Za-z\s]+)([\d]+:[\d]+)?(\s[\d\.]+)?'

@threaded
@match(regex=TRAVEL_REGEX)
def line_match(event, f, t, time=None, date=None, *args):
    """Search for mhd in BA or bus/train lines in Slovakia

    Examples:
        bus z mlyny na hlst
        vlak z BA do TO
        bus z BA do LM 18:00 20.12.2014
        spoj zo Zochova no mlyny
    """
    msg = event.meta['body']

    if f == t:
        return 'Not in this universe.'

    time = '' if time is None else time
    date = '' if date is None else date

    if ('zajtra' in msg or 'pozajtra' in msg) and date is not '':
        if 'pozajtra' in msg:
            delta = 2
        elif 'zajtra' in msg:
            delta = 1
        date = (datetime.date.today() + datetime.timedelta(days=delta)) \
            .strftime("%d.%m.%Y")

    vehicle = 'vlakbus'
    if 'bus' in msg:
        vehicle = "bus"
    elif 'vlak' in msg:
        vehicle = 'vlak'

    r = cpsk.get_routes(f, t, vehicle=vehicle, time=time, date=date)
    if not len(r):
        f = imhdsk.clear_stop(imhdsk.suggest(
                              rootify(f.split(' ')[0]))[0]['name'])
        t = imhdsk.clear_stop(imhdsk.suggest(
                              rootify(t.split(' ')[0]))[0]['name'])

        r = imhdsk.routes(f, t, time=time, date=date)

    return send_output(event.meta['nick'], f, t, date, result=r)

def get_line(event, vehicle):
    """Searches for bus/train based on given vehicle argument"""
    args = event.args
    if len(args) >= 1 and args[0] == 'next':
        if not event.meta['nick'] in searched:
            return 'No next line'
        args = searched_incrementer(event.meta['nick'])

    if len(args) < 2:
        return 'Not enough arguments specified. See !help for usage'
    if '-' in args:
        args = split_args_by(args, '-')

    dep = args[0]
    dest = args[1]

    time = args[2] if len(args) > 2 else ''
    date = args[3] if len(args) > 3 else ''

    if dep == dest:
        return "You joker"

    r = cpsk.get_routes(dep, dest, vehicle=vehicle, time=time, date=date)
    return send_output(event.meta['nick'], dep, dest, date, result=r)

@threaded
@cmd
def bus(event):
    """Search for next bus line from A to B

    Examples:
        !bus BA TO
        !bus Kosice - Bratislava - 19:00 - 20.12.2014
    """

    return get_line(event, 'bus')

@threaded
@cmd
def vlak(event):
    """Search for next train line from A to B

    Examples:
        !vlak Kosice Bratislava
        !vlak Kosice - Bratislava - 19:00 - 20.12.2014
    """
    return get_line(event, 'vlak')

@threaded
@cmd
def spoj(event):
    """Search for next means of transportation from A to B

    Examples:
        !spoj Kosice Bratislava
        !spoj Kosice - Bratislava - 19:00 - 24.12.2014
    """
    return get_line(event, 'vlakbus')
<|endoftext|>