<commit_before># Copyright (c) 2009-2012, Andrew McNabb
# Copyright (c) 2013, Kristoffer Gronlund

from errno import EINTR
from subprocess import Popen, PIPE
import os
import signal
import sys
import time
import traceback

from psshlib import askpass_client

BUFFER_SIZE = 1 << 16

try:
    bytes
except NameError:
    bytes = str

class Task(object):
    """Starts a process and manages its input and output.

    Upon completion, the `exitstatus` attribute is set to the exit status
    of the process.
    """
    def __init__(self,
                 host,
                 port,
                 user,
                 cmd,
                 verbose=False,
                 quiet=False,
                 stdin=None,
                 print_out=False,
                 inline=False,
                 inline_stdout=False,
                 default_user=None):

        # Backwards compatibility:
        if not isinstance(verbose, bool):
            opts = verbose
            verbose = opts.verbose
            quiet = opts.quiet
            try:
                print_out = bool(opts.print_out)
            except AttributeError:
                print_out = False
            try:
                inline = bool(opts.inline)
            except AttributeError:
                inline = False
            try:
                inline_stdout = bool(opts.inline_stdout)
            except AttributeError:
                inline_stdout = False
            default_user = opts.user

        self.exitstatus = None

        self.host = host
        self.pretty_host = host
        self.port = port
        self.cmd = cmd

        if user and user != default_user:
            self.pretty_host = '@'.join((user, self.pretty_host))
        if port:
            self.pretty_host = ':'.join((self.pretty_host, port))

        self.proc = None
        self.writer = None
        self.timestamp = None
        self.failures = []
        self.killed = False
        self.inputbuffer = stdin
        self.byteswritten = 0
        self.outputbuffer = bytes()
        self.errorbuffer = bytes()

        self.stdin = None
        self.stdout = None
        self.stderr = None
        self.outfile = None
        self.errfile = None

        # Set options.
        self.verbose = verbose
        self.quiet = quiet
        self.print_out = print_out
        self.inline = inline
        self.inline_stdout = inline_stdout

    def start(self, nodenum, iomap, writer, askpass_socket=None):
        """Starts the process and registers files with the IOMap."""
        self.writer = writer

        if writer:
            self.outfile, self.errfile = writer.open_files(self.pretty_host)

        # Set up the environment.
        environ = dict(os.environ)
        environ['PSSH_NODENUM'] = str(nodenum)
        environ['PSSH_HOST'] = self.host
        # Disable the GNOME pop-up password dialog and allow ssh to use
        # askpass.py to get a provided password.  If the module file is
        # askpass.pyc, we replace the extension.
        environ['SSH_ASKPASS'] = askpass_client.executable_path()
        if askpass_socket:
            environ['PSSH_ASKPASS_SOCKET'] = askpass_socket
        if self.verbose:
            environ['PSSH_ASKPASS_VERBOSE'] = '1'
        # Work around a mis-feature in ssh where it won't call SSH_ASKPASS
        # if DISPLAY is unset.
        if 'DISPLAY' not in environ:
            environ['DISPLAY'] = 'pssh-gibberish'

        # Create the subprocess.  Since we carefully call set_cloexec() on
        # all open files, we specify close_fds=False.
        self.proc = Popen(self.cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE,
                close_fds=False, preexec_fn=os.setsid, env=environ)
        self.timestamp = time.time()
        if self.inputbuffer:
            self.stdin = self.proc.stdin
            iomap.register_write(self.stdin.fileno(), self.handle_stdin)
        else:
            self.proc.stdin.close()
        self.stdout = self.proc.stdout
        iomap.register_read(self.stdout.fileno(), self.handle_stdout)
        self.stderr = self.proc.stderr
        iomap.register_read(self.stderr.fileno(), self.handle_stderr)

    def _kill(self):
        """Signals the process to terminate."""
        if self.proc:
            try:
                os.kill(-self.proc.pid, signal.SIGKILL)
            except OSError:
                # If the kill fails, then just assume the process is dead.
                pass
            self.killed = True

    def timedout(self):
        """Kills the process and registers a timeout error."""
        if not self.killed:
            self._kill()
            self.failures.append('Timed out')

    def interrupted(self):
        """Kills the process and registers an keyboard interrupt error."""
        if not self.killed:
            self._kill()
            self.failures.append('Interrupted')

    def cancel(self):
        """Stops a task that has not started."""
        self.failures.append('Cancelled')

    def elapsed(self):
        """Finds the time in seconds since the process was started."""
        return time.time() - self.timestamp

    def running(self):
        """Finds if the process has terminated and saves the return code."""
        if self.stdin or self.stdout or self.stderr:
            return True
        if self.proc:
            self.exitstatus = self.proc.poll()
            if self.exitstatus is None:
                if self.killed:
                    # Set the exitstatus to what it would be if we waited.
                    self.exitstatus = -signal.SIGKILL
                    return False
                else:
                    return True
            else:
                if self.exitstatus < 0:
                    message = 'Killed by signal %s' % (-self.exitstatus)
                    self.failures.append(message)
                elif self.exitstatus > 0:
                    message = 'Exited with error code %s' % self.exitstatus
                    self.failures.append(message)
                self.proc = None
                return False

    def handle_stdin(self, fd, iomap):
        """Called when the process's standard input is ready for writing."""
        try:
            start = self.byteswritten
            if start < len(self.inputbuffer):
                chunk = self.inputbuffer[start:start+BUFFER_SIZE]
                self.byteswritten = start + os.write(fd, chunk)
            else:
                self.close_stdin(iomap)
        except (OSError, IOError):
            _, e, _ = sys.exc_info()
            if e.errno != EINTR:
                self.close_stdin(iomap)
                self.log_exception(e)

    def close_stdin(self, iomap):
        if self.stdin:
            iomap.unregister(self.stdin.fileno())
            self.stdin.close()
            self.stdin = None

    def handle_stdout(self, fd, iomap):
        """Called when the process's standard output is ready for reading."""
        try:
            buf = os.read(fd, BUFFER_SIZE)
            if buf:
                if self.inline or self.inline_stdout:
                    if self.quiet:
                        self.outputbuffer += "%s: %s" % (self.host, buf)
                    else:
                        self.outputbuffer += buf
                if self.outfile:
                    self.writer.write(self.outfile, buf)
                if self.print_out:
                    sys.stdout.write('%s: %s' % (self.host, buf))
                    if buf[-1] != '\n':
                        sys.stdout.write('\n')
            else:
                self.close_stdout(iomap)
        except (OSError, IOError):
            _, e, _ = sys.exc_info()
            if e.errno != EINTR:
                self.close_stdout(iomap)
                self.log_exception(e)

    def close_stdout(self, iomap):
        if self.stdout:
            iomap.unregister(self.stdout.fileno())
            self.stdout.close()
            self.stdout = None
        if self.outfile:
            self.writer.close(self.outfile)
            self.outfile = None

    def handle_stderr(self, fd, iomap):
        """Called when the process's standard error is ready for reading."""
        try:
            buf = os.read(fd, BUFFER_SIZE)
            if buf:
                if self.inline:
                    self.errorbuffer += buf
                if self.errfile:
                    self.writer.write(self.errfile, buf)
            else:
                self.close_stderr(iomap)
        except (OSError, IOError):
            _, e, _ = sys.exc_info()
            if e.errno != EINTR:
                self.close_stderr(iomap)
                self.log_exception(e)

    def close_stderr(self, iomap):
        if self.stderr:
            iomap.unregister(self.stderr.fileno())
            self.stderr.close()
            self.stderr = None
        if self.errfile:
            self.writer.close(self.errfile)
            self.errfile = None

    def log_exception(self, e):
        """Saves a record of the most recent exception for error reporting."""
        if self.verbose:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            exc = ("Exception: %s, %s, %s" %
                    (exc_type, exc_value, traceback.format_tb(exc_traceback)))
        else:
            exc = str(e)
        self.failures.append(exc)

# vim:ts=4:sw=4:et:

<commit_msg>Prepend hostname on each line when -P is set<commit_after># Copyright (c) 2009-2012, Andrew McNabb
# Copyright (c) 2013, Kristoffer Gronlund

from errno import EINTR
from subprocess import Popen, PIPE
import os
import signal
import sys
import time
import traceback

from psshlib import askpass_client

BUFFER_SIZE = 1 << 16

try:
    bytes
except NameError:
    bytes = str

class Task(object):
    """Starts a process and manages its input and output.

    Upon completion, the `exitstatus` attribute is set to the exit status
    of the process.
    """
    def __init__(self,
                 host,
                 port,
                 user,
                 cmd,
                 verbose=False,
                 quiet=False,
                 stdin=None,
                 print_out=False,
                 inline=False,
                 inline_stdout=False,
                 default_user=None):

        # Backwards compatibility:
        if not isinstance(verbose, bool):
            opts = verbose
            verbose = opts.verbose
            quiet = opts.quiet
            try:
                print_out = bool(opts.print_out)
            except AttributeError:
                print_out = False
            try:
                inline = bool(opts.inline)
            except AttributeError:
                inline = False
            try:
                inline_stdout = bool(opts.inline_stdout)
            except AttributeError:
                inline_stdout = False
            default_user = opts.user

        self.exitstatus = None

        self.host = host
        self.pretty_host = host
        self.port = port
        self.cmd = cmd

        if user and user != default_user:
            self.pretty_host = '@'.join((user, self.pretty_host))
        if port:
            self.pretty_host = ':'.join((self.pretty_host, port))

        self.proc = None
        self.writer = None
        self.timestamp = None
        self.failures = []
        self.killed = False
        self.inputbuffer = stdin
        self.byteswritten = 0
        self.outputbuffer = bytes()
        self.errorbuffer = bytes()

        self.stdin = None
        self.stdout = None
        self.stderr = None
        self.outfile = None
        self.errfile = None

        # Set options.
        self.verbose = verbose
        self.quiet = quiet
        self.print_out = print_out
        self.inline = inline
        self.inline_stdout = inline_stdout

    def start(self, nodenum, iomap, writer, askpass_socket=None):
        """Starts the process and registers files with the IOMap."""
        self.writer = writer

        if writer:
            self.outfile, self.errfile = writer.open_files(self.pretty_host)

        # Set up the environment.
        environ = dict(os.environ)
        environ['PSSH_NODENUM'] = str(nodenum)
        environ['PSSH_HOST'] = self.host
        # Disable the GNOME pop-up password dialog and allow ssh to use
        # askpass.py to get a provided password.  If the module file is
        # askpass.pyc, we replace the extension.
        environ['SSH_ASKPASS'] = askpass_client.executable_path()
        if askpass_socket:
            environ['PSSH_ASKPASS_SOCKET'] = askpass_socket
        if self.verbose:
            environ['PSSH_ASKPASS_VERBOSE'] = '1'
        # Work around a mis-feature in ssh where it won't call SSH_ASKPASS
        # if DISPLAY is unset.
        if 'DISPLAY' not in environ:
            environ['DISPLAY'] = 'pssh-gibberish'

        # Create the subprocess.  Since we carefully call set_cloexec() on
        # all open files, we specify close_fds=False.
        self.proc = Popen(self.cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE,
                close_fds=False, preexec_fn=os.setsid, env=environ)
        self.timestamp = time.time()
        if self.inputbuffer:
            self.stdin = self.proc.stdin
            iomap.register_write(self.stdin.fileno(), self.handle_stdin)
        else:
            self.proc.stdin.close()
        self.stdout = self.proc.stdout
        iomap.register_read(self.stdout.fileno(), self.handle_stdout)
        self.stderr = self.proc.stderr
        iomap.register_read(self.stderr.fileno(), self.handle_stderr)

    def _kill(self):
        """Signals the process to terminate."""
        if self.proc:
            try:
                os.kill(-self.proc.pid, signal.SIGKILL)
            except OSError:
                # If the kill fails, then just assume the process is dead.
                pass
            self.killed = True

    def timedout(self):
        """Kills the process and registers a timeout error."""
        if not self.killed:
            self._kill()
            self.failures.append('Timed out')

    def interrupted(self):
        """Kills the process and registers an keyboard interrupt error."""
        if not self.killed:
            self._kill()
            self.failures.append('Interrupted')

    def cancel(self):
        """Stops a task that has not started."""
        self.failures.append('Cancelled')

    def elapsed(self):
        """Finds the time in seconds since the process was started."""
        return time.time() - self.timestamp

    def running(self):
        """Finds if the process has terminated and saves the return code."""
        if self.stdin or self.stdout or self.stderr:
            return True
        if self.proc:
            self.exitstatus = self.proc.poll()
            if self.exitstatus is None:
                if self.killed:
                    # Set the exitstatus to what it would be if we waited.
                    self.exitstatus = -signal.SIGKILL
                    return False
                else:
                    return True
            else:
                if self.exitstatus < 0:
                    message = 'Killed by signal %s' % (-self.exitstatus)
                    self.failures.append(message)
                elif self.exitstatus > 0:
                    message = 'Exited with error code %s' % self.exitstatus
                    self.failures.append(message)
                self.proc = None
                return False

    def handle_stdin(self, fd, iomap):
        """Called when the process's standard input is ready for writing."""
        try:
            start = self.byteswritten
            if start < len(self.inputbuffer):
                chunk = self.inputbuffer[start:start+BUFFER_SIZE]
                self.byteswritten = start + os.write(fd, chunk)
            else:
                self.close_stdin(iomap)
        except (OSError, IOError):
            _, e, _ = sys.exc_info()
            if e.errno != EINTR:
                self.close_stdin(iomap)
                self.log_exception(e)

    def close_stdin(self, iomap):
        if self.stdin:
            iomap.unregister(self.stdin.fileno())
            self.stdin.close()
            self.stdin = None

    def handle_stdout(self, fd, iomap):
        """Called when the process's standard output is ready for reading."""
        try:
            buf = os.read(fd, BUFFER_SIZE)
            if buf:
                if self.inline or self.inline_stdout:
                    if self.quiet:
                        self.outputbuffer += "%s: %s" % (self.host, buf)
                    else:
                        self.outputbuffer += buf
                if self.outfile:
                    self.writer.write(self.outfile, buf)
                if self.print_out:
                    for l in buf.split('\n'):
                        sys.stdout.write("%s: %s\n" % (self.host, l))
            else:
                self.close_stdout(iomap)
        except (OSError, IOError):
            _, e, _ = sys.exc_info()
            if e.errno != EINTR:
                self.close_stdout(iomap)
                self.log_exception(e)

    def close_stdout(self, iomap):
        if self.stdout:
            iomap.unregister(self.stdout.fileno())
            self.stdout.close()
            self.stdout = None
        if self.outfile:
            self.writer.close(self.outfile)
            self.outfile = None

    def handle_stderr(self, fd, iomap):
        """Called when the process's standard error is ready for reading."""
        try:
            buf = os.read(fd, BUFFER_SIZE)
            if buf:
                if self.inline:
                    self.errorbuffer += buf
                if self.errfile:
                    self.writer.write(self.errfile, buf)
            else:
                self.close_stderr(iomap)
        except (OSError, IOError):
            _, e, _ = sys.exc_info()
            if e.errno != EINTR:
                self.close_stderr(iomap)
                self.log_exception(e)

    def close_stderr(self, iomap):
        if self.stderr:
            iomap.unregister(self.stderr.fileno())
            self.stderr.close()
            self.stderr = None
        if self.errfile:
            self.writer.close(self.errfile)
            self.errfile = None

    def log_exception(self, e):
        """Saves a record of the most recent exception for error reporting."""
        if self.verbose:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            exc = ("Exception: %s, %s, %s" %
                    (exc_type, exc_value, traceback.format_tb(exc_traceback)))
        else:
            exc = str(e)
        self.failures.append(exc)

# vim:ts=4:sw=4:et:

<|endoftext|>


<commit_before>from django.conf.urls import url
from django.views.generic import ListView, DetailView
from django.views.generic.base import TemplateView

from django.contrib.auth.decorators import login_required
from .decorators import provider_required, clintype_required, provider_update_required
from . import models as mymodels
from . import views

# pylint: disable=I0011

unwrapped_urlpatterns = [  # pylint: disable=invalid-name
    url(r'^$',
        views.home_page,
        name="home"),
    url(r'^all/$',
        views.all_patients,
        name="all-patients"),
    url(r'^phone_directory/$',
        views.phone_directory,
        name="phone-directory"),
    url(r'^intake/$',
        views.PatientCreate.as_view(),
        name="intake"),
    url(r'^(?P<pk>[0-9]+)/$',
        views.patient_detail,
        name='patient-detail'),
    url(r'^patient/update/(?P<pk>[0-9]+)$',
        views.PatientUpdate.as_view(),
        name='patient-update'),
    url(r'^patient/activate_detail/(?P<pk>[0-9]+)$',
        views.patient_activate_detail,
        name='patient-activate-detail'),
    url(r'^patient/activate_home/(?P<pk>[0-9]+)$',
        views.patient_activate_home,
        name='patient-activate-home'),

    # PROVIDERS
    url(r'^new-provider/$',
        views.ProviderCreate.as_view(),
        name='new-provider'),
    url(r'^choose-role/$',
        views.choose_clintype,
        name='choose-clintype'),
    url(r'^provider-update/$',
        views.ProviderUpdate.as_view(),
        name='provider-update'),

    # ACTION ITEMS
    url(r'^(?P<pt_id>[0-9]+)/action-item/$',
        views.ActionItemCreate.as_view(),
        name='new-action-item'),
    url(r'^action-item/(?P<pk>[0-9]+)/update$',
        views.ActionItemUpdate.as_view(),
        name="update-action-item"),
    url(r'^action-item/(?P<ai_id>[0-9]+)/done$',
        views.done_action_item,
        name='done-action-item'),
    url(r'^action-item/(?P<ai_id>[0-9]+)/reset$',
        views.reset_action_item,
        name='reset-action-item'),

    # DOCUMENTS
    url(r'^(?P<pt_id>[0-9]+)/document/$',
        views.DocumentCreate.as_view(),
        name="new-document"),
    url(r'^document/(?P<pk>[0-9]+)$',
        DetailView.as_view(model=mymodels.Document),
        name="document-detail"),
    url(r'^document/update/(?P<pk>[0-9]+)$',
        views.DocumentUpdate.as_view(),
        name="document-update"),

    # MISC
    url(r'^about/',
        TemplateView.as_view(template_name='pttrack/about.html'),
        name='about'),
]

def wrap_url(url, no_wrap=[], login_only=[], provider_only=[]):
    '''
    Wrap URL in decorators as appropriate.
    '''
    if url.name in login_only:
        # do not wrap in full regalia
        url._callback = login_required(url._callback)
    elif url.name in provider_only:
        # callback = url._callback
        url._callback = provider_required(url._callback)
        url._callback = login_required(url._callback)
        # url._callback = callback
    elif url.name in no_wrap:
        # do not wrap at all, fully public
        pass
    else:  # wrap in everything
        url._callback = clintype_required(url._callback)
        url._callback = provider_update_required(url._callback)
        url._callback = provider_required(url._callback)
        url._callback = login_required(url._callback)

    return url

wrap_config = {'no_wrap': ['about'],
               'login_only': ['new-provider', 'choose-clintype'],
               'provider_only': ['provider-update']}

urlpatterns = [wrap_url(url, **wrap_config) for url in unwrapped_urlpatterns]
<commit_msg>even better url_wrap<commit_after>from django.conf.urls import url
from django.views.generic import ListView, DetailView
from django.views.generic.base import TemplateView

from django.contrib.auth.decorators import login_required
from .decorators import provider_required, clintype_required, provider_update_required
from . import models as mymodels
from . import views

# pylint: disable=I0011

unwrapped_urlpatterns = [  # pylint: disable=invalid-name
    url(r'^$',
        views.home_page,
        name="home"),
    url(r'^all/$',
        views.all_patients,
        name="all-patients"),
    url(r'^phone_directory/$',
        views.phone_directory,
        name="phone-directory"),
    url(r'^intake/$',
        views.PatientCreate.as_view(),
        name="intake"),
    url(r'^(?P<pk>[0-9]+)/$',
        views.patient_detail,
        name='patient-detail'),
    url(r'^patient/update/(?P<pk>[0-9]+)$',
        views.PatientUpdate.as_view(),
        name='patient-update'),
    url(r'^patient/activate_detail/(?P<pk>[0-9]+)$',
        views.patient_activate_detail,
        name='patient-activate-detail'),
    url(r'^patient/activate_home/(?P<pk>[0-9]+)$',
        views.patient_activate_home,
        name='patient-activate-home'),

    # PROVIDERS
    url(r'^new-provider/$',
        views.ProviderCreate.as_view(),
        name='new-provider'),
    url(r'^choose-role/$',
        views.choose_clintype,
        name='choose-clintype'),
    url(r'^provider-update/$',
        views.ProviderUpdate.as_view(),
        name='provider-update'),

    # ACTION ITEMS
    url(r'^(?P<pt_id>[0-9]+)/action-item/$',
        views.ActionItemCreate.as_view(),
        name='new-action-item'),
    url(r'^action-item/(?P<pk>[0-9]+)/update$',
        views.ActionItemUpdate.as_view(),
        name="update-action-item"),
    url(r'^action-item/(?P<ai_id>[0-9]+)/done$',
        views.done_action_item,
        name='done-action-item'),
    url(r'^action-item/(?P<ai_id>[0-9]+)/reset$',
        views.reset_action_item,
        name='reset-action-item'),

    # DOCUMENTS
    url(r'^(?P<pt_id>[0-9]+)/document/$',
        views.DocumentCreate.as_view(),
        name="new-document"),
    url(r'^document/(?P<pk>[0-9]+)$',
        DetailView.as_view(model=mymodels.Document),
        name="document-detail"),
    url(r'^document/update/(?P<pk>[0-9]+)$',
        views.DocumentUpdate.as_view(),
        name="document-update"),

    # MISC
    url(r'^about/',
        TemplateView.as_view(template_name='pttrack/about.html'),
        name='about'),
]

def wrap_url(url, no_wrap=[], login_only=[], provider_only=[], updated_provider_only=[]):
    '''
    Wrap URL in decorators as appropriate.
    '''
    if url.name in no_wrap:
        # do not wrap at all, fully public
        pass

    elif url.name in login_only:
        url._callback = login_required(url._callback)

    elif url.name in provider_only:
        url._callback = provider_required(url._callback)
        url._callback = login_required(url._callback)

    elif url.name in updated_provider_only:
        url._callback = provider_update_required(url._callback)
        url._callback = provider_required(url._callback)
        url._callback = login_required(url._callback)

    else:  # wrap in everything
        url._callback = clintype_required(url._callback)
        url._callback = provider_update_required(url._callback)
        url._callback = provider_required(url._callback)
        url._callback = login_required(url._callback)

    return url

wrap_config = {'no_wrap': ['about'],
               'login_only': ['new-provider'],
               'provider_only': ['provider-update'],
               'updated_provider_only': ['choose-clintype']}

urlpatterns = [wrap_url(url, **wrap_config) for url in unwrapped_urlpatterns]
<|endoftext|>


<commit_before>"""
Copyright (c) 2019 Red Hat, Inc
All rights reserved.

This software may be modified and distributed under the terms
of the BSD license. See the LICENSE file for details.
"""
from __future__ import print_function, unicode_literals, absolute_import

import tempfile

from atomic_reactor.build import BuildResult
from atomic_reactor.constants import PLUGIN_SOURCE_CONTAINER_KEY
from atomic_reactor.plugin import BuildStepPlugin
from atomic_reactor.plugins.pre_reactor_config import get_value

class SourceContainerPlugin(BuildStepPlugin):
    """
    Build source container image using
    https://github.com/containers/BuildSourceImage

    Image https://quay.io/repository/ctrs/bsi should be pushed to image stream
    on OCP instance and image name must be specified in config
    option `source_builder_image`
    """

    key = PLUGIN_SOURCE_CONTAINER_KEY

    def get_builder_image(self):
        source_containers_conf = get_value(self.workflow, 'source_containers', {})
        return source_containers_conf.get('source_builder_image')

    def run(self):
        """Build image inside current environment.
        It's expected this may run within (privileged) docker container.

        Returns:
            BuildResult
        """
        source_data_dir = tempfile.mkdtemp()  # TODO: from pre_* plugin
        # TODO fail when source dir is empty

        image_output_dir = tempfile.mkdtemp()
        image = self.get_builder_image()
        if not image:
            raise RuntimeError(
                'Cannot build source containers, builder image is not '
                'specified in configuration')

        srpms_path = '/data/'
        output_path = '/output/'

        volume_bindings = {
            source_data_dir: {
                'bind': srpms_path,
                'mode': 'ro,Z',
            },
            image_output_dir: {
                'bind': output_path,
                'mode': 'rw,Z',
            }
        }

        command = '-d sourcedriver_rpm_dir -s {srpms_path} -o {output_path}'.format(
            srpms_path=srpms_path,
            output_path=output_path,
        )
        container_id = self.tasker.run(
            image,
            volume_bindings=volume_bindings,
            command=command
        )
        response = self.tasker.wait(container_id)
        output = self.tasker.logs(container_id)

        self.tasker.cleanup_containers(container_id)

        status_code = response['StatusCode']
        if status_code != 0:
            reason = (
                "Source container build failed with error code {}. "
                "See build logs for details".format(status_code)
            )
            return BuildResult(logs=output, fail_reason=reason)

        return BuildResult(
            logs=output,
            oci_image_path=image_output_dir,
            skip_layer_squash=True
        )
<commit_msg>Source container build: pull image first<commit_after>"""
Copyright (c) 2019 Red Hat, Inc
All rights reserved.

This software may be modified and distributed under the terms
of the BSD license. See the LICENSE file for details.
"""
from __future__ import print_function, unicode_literals, absolute_import

import tempfile

from atomic_reactor.build import BuildResult, ImageName
from atomic_reactor.constants import PLUGIN_SOURCE_CONTAINER_KEY
from atomic_reactor.plugin import BuildStepPlugin
from atomic_reactor.plugins.pre_reactor_config import get_value

class SourceContainerPlugin(BuildStepPlugin):
    """
    Build source container image using
    https://github.com/containers/BuildSourceImage

    Image https://quay.io/repository/ctrs/bsi should be pushed to image stream
    on OCP instance and image name must be specified in config
    option `source_builder_image`
    """

    key = PLUGIN_SOURCE_CONTAINER_KEY

    def get_builder_image(self):
        source_containers_conf = get_value(self.workflow, 'source_containers', {})
        return source_containers_conf.get('source_builder_image')

    def run(self):
        """Build image inside current environment.
        It's expected this may run within (privileged) docker container.

        Returns:
            BuildResult
        """
        source_data_dir = tempfile.mkdtemp()  # TODO: from pre_* plugin
        # TODO fail when source dir is empty

        image_output_dir = tempfile.mkdtemp()
        image = self.get_builder_image()
        if not image:
            raise RuntimeError(
                'Cannot build source containers, builder image is not '
                'specified in configuration')

        image = ImageName.parse(image)

        srpms_path = '/data/'
        output_path = '/output/'

        volume_bindings = {
            source_data_dir: {
                'bind': srpms_path,
                'mode': 'ro,Z',
            },
            image_output_dir: {
                'bind': output_path,
                'mode': 'rw,Z',
            }
        }

        pulled_img = self.tasker.pull_image(image)

        command = '-d sourcedriver_rpm_dir -s {srpms_path} -o {output_path}'.format(
            srpms_path=srpms_path,
            output_path=output_path,
        )
        container_id = self.tasker.run(
            pulled_img,
            volume_bindings=volume_bindings,
            command=command
        )
        response = self.tasker.wait(container_id)
        output = self.tasker.logs(container_id, stream=False)

        self.log.debug("Build log:\n%s", "\n".join(output))

        self.tasker.cleanup_containers(container_id)

        status_code = response['StatusCode']
        if status_code != 0:
            reason = (
                "Source container build failed with error code {}. "
                "See build logs for details".format(status_code)
            )
            return BuildResult(logs=output, fail_reason=reason)

        return BuildResult(
            logs=output,
            oci_image_path=image_output_dir,
            skip_layer_squash=True
        )
<|endoftext|>


<commit_before>def tolist(x):
    return x if isinstance(x, list) else [x]

def index():
    response.view = 'default/data.json'
    response.headers['Access-Control-Allow-Origin'] = '*'

    query = (db.brca_variant.Variant_Source.upper().contains([request.vars.source.upper()]))
    direction = request.vars.direction
    order_by = getattr(db.brca_variant, request.vars.order_by)
    order_by_dir = order_by if direction == 'descending' else ~order_by
    page_size = int(request.vars.page_size)
    page_num = int(request.vars.page_num)
    limit_by = (page_size * page_num, page_size * (page_num + 1))

    if request.vars.search_term:
        search_term = request.vars.search_term.upper()
        search_columns = tolist(request.vars.search_column)
        term = lambda c: getattr(db.brca_variant, c).upper().contains([search_term])

        subquery = term(search_columns[0])
        for c in search_columns[1:]:
            subquery |= term(c)

        query &= subquery

    if request.vars.filter:
        filters = zip(tolist(request.vars.filter), tolist(request.vars.filterValue))
        for (p, v) in filters:
            query &= getattr(db.brca_variant, p) == v

    brca_data = db(query).select(orderby=order_by_dir, limitby=limit_by)
    count = db(query).count()

    return dict(data=brca_data, count=count)
<commit_msg>Fix order.<commit_after>def tolist(x):
    return x if isinstance(x, list) else [x]

def index():
    response.view = 'default/data.json'
    response.headers['Access-Control-Allow-Origin'] = '*'

    query = (db.brca_variant.Variant_Source.upper().contains([request.vars.source.upper()]))
    direction = request.vars.direction
    order_by = getattr(db.brca_variant, request.vars.order_by)
    order_by_dir = ~order_by if direction == 'descending' else order_by
    page_size = int(request.vars.page_size)
    page_num = int(request.vars.page_num)
    limit_by = (page_size * page_num, page_size * (page_num + 1))

    if request.vars.search_term:
        search_term = request.vars.search_term.upper()
        search_columns = tolist(request.vars.search_column)
        term = lambda c: getattr(db.brca_variant, c).upper().contains([search_term])

        subquery = term(search_columns[0])
        for c in search_columns[1:]:
            subquery |= term(c)

        query &= subquery

    if request.vars.filter:
        filters = zip(tolist(request.vars.filter), tolist(request.vars.filterValue))
        for (p, v) in filters:
            query &= getattr(db.brca_variant, p) == v

    brca_data = db(query).select(orderby=order_by_dir, limitby=limit_by)
    count = db(query).count()

    return dict(data=brca_data, count=count)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

"""

This module contains the Graph Cache Manager

"""

import logging

from . import models
from .base_cache import BaseCacheManager
from .utils import parse_datetime
from ..canonicalize import decanonicalize_edge, decanonicalize_node
from ..constants import *
from ..io import to_bytes, from_bytes

try:
    import cPickle as pickle
except ImportError:
    import pickle

log = logging.getLogger(__name__)

class GraphCacheManager(BaseCacheManager):
    def insert_graph(self, graph, store_parts=False):
        """Stores a graph in the database

        :param graph: a BEL network
        :type graph: pybel.BELGraph
        :param store_parts: Should the graph be stored in the Edge Store?
        :type store_parts: bool
        :return: A Network object
        :rtype: models.Network
        """
        graph_bytes = to_bytes(graph)

        network = models.Network(blob=graph_bytes, **graph.document)

        if store_parts:
            self.store_graph_parts(network, graph)

        self.session.add(network)
        self.session.commit()

        return network

    def store_graph_parts(self, network, graph):
        """Stores the given graph into the Edge Store

        :param network: A SQLAlchemy PyBEL Network objet
        :type network: models.Network
        :param graph: A BEL Graph
        :type graph: pybel.BELGraph
        """
        nc = {node: self.get_or_create_node(graph, node) for node in graph.nodes_iter()}

        for u, v, k, data in graph.edges_iter(data=True, keys=True):
            source, target = nc[u], nc[v]

            if CITATION not in data or EVIDENCE not in data:
                continue

            citation = self.get_or_create_citation(**data[CITATION])
            evidence = self.get_or_create_evidence(citation, data[EVIDENCE])

            bel = decanonicalize_edge(graph, u, v, k)
            edge = models.Edge(
                source=source,
                target=target,
                relation=data[RELATION],
                evidence=evidence,
                bel=bel,
                blob=pickle.dumps(data)
            )

            for key, value in data[ANNOTATIONS].items():
                if key in graph.annotation_url:
                    url = graph.annotation_url[key]
                    edge.annotations.append(self.get_bel_annotation_entry(url, value))

            network.edges.append(edge)

    def get_bel_annotation_entry(self, url, value):
        """Gets a given AnnotationEntry

        :param url: The url of the annotation source
        :type url: str
        :param value: The value of the annotation from the given url's document
        :type value: str
        :return: An AnnotationEntry object
        :rtype: models.AnnotationEntry
        """
        annotation = self.session.query(models.Annotation).filter_by(url=url).one()
        return self.session.query(models.AnnotationEntry).filter_by(annotation=annotation, name=value).one()

    def get_or_create_evidence(self, citation, text):
        """Creates entry for given evidence if it does not exist.

        :param citation: Citation object obtained from get_or_create_citation()
        :type citation: models.Citation
        :param text: Evidence text
        :type text: str
        :return: An Evidence object
        :rtype: models.Evidence
        """

        result = self.session.query(models.Evidence).filter_by(text=text).one_or_none()

        if result is None:
            result = models.Evidence(text=text, citation=citation)
            self.session.add(result)
            self.session.flush()
            # self.session.commit()  # TODO remove?

        return result

    def get_or_create_node(self, graph, node):
        """Creates entry for given node if it does not exist.

        :param graph: A BEL network
        :type graph: pybel.BELGraph
        :param node: Key for the node to insert.
        :type node: tuple
        :return: A Node object
        :rtype: models.Node
        """
        bel = decanonicalize_node(graph, node)
        blob = pickle.dumps(graph.node[node])

        result = self.session.query(models.Node).filter_by(bel=bel).one_or_none()

        if result is None:
            result = models.Node(bel=bel, blob=blob)
            self.session.add(result)

        return result

    def get_or_create_edge(self, source, target, evidence, bel, relation):
        """Creates entry for given edge if it does not exist.

        :param source: Source node of the relation
        :type source: models.Node
        :param target: Target node of the relation
        :type target: models.Node
        :param evidence: Evidence object that proves the given relation
        :type evidence: models.Evidence
        :param bel: BEL statement that describes the relation
        :type bel: str
        :param relation: Type of the relation between source and target node
        :type relation: str
        :return: An Edge object
        :rtype: models.Edge
        """
        result = self.session.query(models.Edge).filter_by(bel=bel).one_or_none()

        if result:
            return result

        result = models.Edge(source=source, target=target, relation=relation, evidence=evidence, bel=bel)

        return result

    def get_or_create_citation(self, type, name, reference, date=None, authors=None, comments=None):
        """Creates entry for given citation if it does not exist.

        :param type: Citation type (e.g. PubMed)
        :type type: str
        :param name: Title of the publication that is cited
        :type name: str
        :param reference: Identifier of the given citation (e.g. PubMed id)
        :type reference: str
        :param date: Date of publication
        :type date: date
        :param authors: List of authors separated by |
        :type authors: str
        :param comments: Comments on the citation
        :type comments: str
        :return: A Citation object
        :rtype: models.Citation
        """

        result = self.session.query(models.Citation).filter_by(type=type, reference=reference).one_or_none()

        if result is None:
            if date is not None:
                date = parse_datetime(date)

            result = models.Citation(type=type, name=name, reference=reference, date=date, comments=comments)

            if authors is not None:
                for author in authors.split('|'):
                    result.authors.append(self.get_or_create_author(author))

            self.session.add(result)

        return result

    def get_or_create_author(self, name):
        """Gets an author by name, or creates one

        :param name: An author's name
        :type name: str
        :return: An Author object
        :rtype: models.Author
        """
        result = self.session.query(models.Author).filter_by(name=name).one_or_none()

        if result:
            return result

        result = models.Author(name=name)
        self.session.add(result)

        return result

    def get_graph_versions(self, name):
        """Returns all of the versions of a graph with the given name"""
        return {x for x, in self.session.query(models.Network.version).filter(models.Network.name == name).all()}

    def get_graph(self, name, version=None):
        """Loads most recent graph, or allows for specification of version

        :param name: The name of the graph
        :type name: str
        :param version: The version string of the graph. If not specified, loads most recent graph added with this name
        :type version: None or str
        :return: A BEL Graph
        :rtype: pybel.BELGraph
        """
        if version is not None:
            n = self.session.query(models.Network).filter(models.Network.name == name,
                                                          models.Network.version == version).one()
        else:
            n = self.session.query(models.Network).filter(models.Network.name == name).order_by(
                models.Network.created.desc()).first()

        return from_bytes(n.blob)

    def drop_graph(self, network_id):
        """Drops a graph by ID

        :param network_id: The network's database id
        :type network_id: int
        """

        # TODO delete with cascade
        self.session.query(models.Network).filter(models.Network.id == network_id).delete()
        self.session.commit()

    def ls(self):
        """Lists network id, network name, and network version triples"""
        return [(network.id, network.name, network.version) for network in self.session.query(models.Network).all()]

    # TODO implement
    def get_by_edge_filter(self, graph, **kwargs):
        """Gets a BEL graph matching the filter parameters

        :param graph: The graph to fill with the data
        :param kwargs: dictionary of {URL: values}
        :return: A BEL Graph
        :rtype: BELGraph
        """
<commit_msg>Added rudimentary graph filter algorithm<commit_after># -*- coding: utf-8 -*-

"""

This module contains the Graph Cache Manager

"""

import logging

from . import models
from .base_cache import BaseCacheManager
from .utils import parse_datetime
from ..canonicalize import decanonicalize_edge, decanonicalize_node
from ..constants import *
from ..graph import BELGraph
from ..io import to_bytes, from_bytes
from ..parser.utils import subdict_matches

try:
    import cPickle as pickle
except ImportError:
    import pickle

log = logging.getLogger(__name__)

class GraphCacheManager(BaseCacheManager):
    def insert_graph(self, graph, store_parts=False):
        """Stores a graph in the database

        :param graph: a BEL network
        :type graph: pybel.BELGraph
        :param store_parts: Should the graph be stored in the Edge Store?
        :type store_parts: bool
        :return: A Network object
        :rtype: models.Network
        """
        graph_bytes = to_bytes(graph)

        network = models.Network(blob=graph_bytes, **graph.document)

        if store_parts:
            self.store_graph_parts(network, graph)

        self.session.add(network)
        self.session.commit()

        return network

    def store_graph_parts(self, network, graph):
        """Stores the given graph into the Edge Store

        :param network: A SQLAlchemy PyBEL Network objet
        :type network: models.Network
        :param graph: A BEL Graph
        :type graph: pybel.BELGraph
        """
        nc = {node: self.get_or_create_node(graph, node) for node in graph.nodes_iter()}

        for u, v, k, data in graph.edges_iter(data=True, keys=True):
            source, target = nc[u], nc[v]

            if CITATION not in data or EVIDENCE not in data:
                continue

            citation = self.get_or_create_citation(**data[CITATION])
            evidence = self.get_or_create_evidence(citation, data[EVIDENCE])

            bel = decanonicalize_edge(graph, u, v, k)
            edge = models.Edge(
                source=source,
                target=target,
                relation=data[RELATION],
                evidence=evidence,
                bel=bel,
                blob=pickle.dumps(data)
            )

            for key, value in data[ANNOTATIONS].items():
                if key in graph.annotation_url:
                    url = graph.annotation_url[key]
                    edge.annotations.append(self.get_bel_annotation_entry(url, value))

            network.edges.append(edge)

    def get_bel_annotation_entry(self, url, value):
        """Gets a given AnnotationEntry

        :param url: The url of the annotation source
        :type url: str
        :param value: The value of the annotation from the given url's document
        :type value: str
        :return: An AnnotationEntry object
        :rtype: models.AnnotationEntry
        """
        annotation = self.session.query(models.Annotation).filter_by(url=url).one()
        return self.session.query(models.AnnotationEntry).filter_by(annotation=annotation, name=value).one()

    def get_or_create_evidence(self, citation, text):
        """Creates entry for given evidence if it does not exist.

        :param citation: Citation object obtained from get_or_create_citation()
        :type citation: models.Citation
        :param text: Evidence text
        :type text: str
        :return: An Evidence object
        :rtype: models.Evidence
        """

        result = self.session.query(models.Evidence).filter_by(text=text).one_or_none()

        if result is None:
            result = models.Evidence(text=text, citation=citation)
            self.session.add(result)
            self.session.flush()
            # self.session.commit()  # TODO remove?

        return result

    def get_or_create_node(self, graph, node):
        """Creates entry for given node if it does not exist.

        :param graph: A BEL network
        :type graph: pybel.BELGraph
        :param node: Key for the node to insert.
        :type node: tuple
        :return: A Node object
        :rtype: models.Node
        """
        bel = decanonicalize_node(graph, node)
        blob = pickle.dumps(graph.node[node])

        result = self.session.query(models.Node).filter_by(bel=bel).one_or_none()

        if result is None:
            result = models.Node(bel=bel, blob=blob)
            self.session.add(result)

        return result

    def get_or_create_edge(self, source, target, evidence, bel, relation):
        """Creates entry for given edge if it does not exist.

        :param source: Source node of the relation
        :type source: models.Node
        :param target: Target node of the relation
        :type target: models.Node
        :param evidence: Evidence object that proves the given relation
        :type evidence: models.Evidence
        :param bel: BEL statement that describes the relation
        :type bel: str
        :param relation: Type of the relation between source and target node
        :type relation: str
        :return: An Edge object
        :rtype: models.Edge
        """
        result = self.session.query(models.Edge).filter_by(bel=bel).one_or_none()

        if result:
            return result

        result = models.Edge(source=source, target=target, relation=relation, evidence=evidence, bel=bel)

        return result

    def get_or_create_citation(self, type, name, reference, date=None, authors=None, comments=None):
        """Creates entry for given citation if it does not exist.

        :param type: Citation type (e.g. PubMed)
        :type type: str
        :param name: Title of the publication that is cited
        :type name: str
        :param reference: Identifier of the given citation (e.g. PubMed id)
        :type reference: str
        :param date: Date of publication
        :type date: date
        :param authors: List of authors separated by |
        :type authors: str
        :param comments: Comments on the citation
        :type comments: str
        :return: A Citation object
        :rtype: models.Citation
        """

        result = self.session.query(models.Citation).filter_by(type=type, reference=reference).one_or_none()

        if result is None:
            if date is not None:
                date = parse_datetime(date)

            result = models.Citation(type=type, name=name, reference=reference, date=date, comments=comments)

            if authors is not None:
                for author in authors.split('|'):
                    result.authors.append(self.get_or_create_author(author))

            self.session.add(result)

        return result

    def get_or_create_author(self, name):
        """Gets an author by name, or creates one

        :param name: An author's name
        :type name: str
        :return: An Author object
        :rtype: models.Author
        """
        result = self.session.query(models.Author).filter_by(name=name).one_or_none()

        if result:
            return result

        result = models.Author(name=name)
        self.session.add(result)

        return result

    def get_graph_versions(self, name):
        """Returns all of the versions of a graph with the given name"""
        return {x for x, in self.session.query(models.Network.version).filter(models.Network.name == name).all()}

    def get_graph(self, name, version=None):
        """Loads most recent graph, or allows for specification of version

        :param name: The name of the graph
        :type name: str
        :param version: The version string of the graph. If not specified, loads most recent graph added with this name
        :type version: None or str
        :return: A BEL Graph
        :rtype: pybel.BELGraph
        """
        if version is not None:
            n = self.session.query(models.Network).filter(models.Network.name == name,
                                                          models.Network.version == version).one()
        else:
            n = self.session.query(models.Network).filter(models.Network.name == name).order_by(
                models.Network.created.desc()).first()

        return from_bytes(n.blob)

    def drop_graph(self, network_id):
        """Drops a graph by ID

        :param network_id: The network's database id
        :type network_id: int
        """

        # TODO delete with cascade
        self.session.query(models.Network).filter(models.Network.id == network_id).delete()
        self.session.commit()

    def ls(self):
        """Lists network id, network name, and network version triples"""
        return [(network.id, network.name, network.version) for network in self.session.query(models.Network).all()]

    def get_edge_iter_by_filter(self, **annotations):
        """Returns an iterator over models.Edge object that match the given annotations

        :param annotations: dictionary of {URL: values}
        :type annotations: dict
        :return: An iterator over models.Edge object that match the given annotations
        :rtype: iter of models.Edge
        """

        # TODO make smarter
        for edge in self.session.query(models.Edge).all():
            ad = {a.annotation.name: a.name for a in edge.annotations}
            if subdict_matches(ad, annotations):
                yield edge

    def get_graph_by_filter(self, **annotations):
        """Fills a BEL graph with edges retrieved from a filter

        :param annotations: dictionary of {URL: values}
        :type annotations: dict
        :return: A BEL Graph
        :rtype: pybel.BELGraph
        """
        graph = BELGraph()

        for edge in self.get_edge_iter_by_filter(**annotations):
            if edge.source.id not in graph:
                graph.add_node(edge.source.id, attr_dict=pickle.loads(edge.source.blob))

            if edge.target.id not in graph:
                graph.add_node(edge.target.id, attr_dict=pickle.loads(edge.target.blob))

            graph.add_edge(edge.source.id, edge.target.id, attr_dict=pickle.loads(edge.blob))

        return graph
<|endoftext|>


<commit_before>from flask import jsonify
import requests
from datetime import datetime

'''
********************************************************************************

This is a way to keep all the corpus stuff in one file. I will refactor later.

======
This section is for databases
======

********************************************************************************
'''

from app import app
from flask.ext.pymongo import PyMongo

app.config['MONGOCORPUS_DBNAME'] = 'affect-corpus'
mongo_corpus = PyMongo(app, config_prefix='MONGOCORPUS')

'''
********************************************************************************

This is a way to keep all the corpus stuff in one file. I will refactor later.

======
This section is for controllers
======

********************************************************************************
'''

'''
The aim of corpus_builder.py is to build a corpus of synonyms around a primary word.

i.e.
Affect
  it has synonyms
     those synonyms have synonyms
       and after the 4th level deep is likely where we don't care.

Moreover, the words will be stored as follows:

{
  "word": <added by what word>
  "response": <json response from bighugelabs>
  "utc": <utc date>
  "flat-list": <list of all words (syn/ant of verb/noun) for this word>
}

This gets stored in a mongo database. Collections are named after the inital parent.
In this case that parent is 'Affect'. To be clear, this is probably not the best way
to build a corpus, but it is a quick and effective way for getting started.
'''

def verify_bhl_api(api_key):
    r = requests.get('http://words.bighugelabs.com/api/2/' + api_key + '/affect/json')
    if(r.raise_for_status()):
        return 'error'
    else:
        return jsonify(r.json())

def get_single_word(api_key, word):
    r = requests.get('http://words.bighugelabs.com/api/2/' + api_key + '/' + word + '/json')
    if(r.raise_for_status()):
        return 'error'
    else:
        return r.json()

def handle_next_level(raw_response):
    print '*************************************'
    print 'next-level'
    print '*************************************'
    va = []
    vs = []
    na = []
    ns = []
    if(raw_response.get('verb')):
        va = raw_response.get('verb').get('ant') if raw_response.get('verb').get('ant') is not None else []
        print va
        vs = raw_response.get('verb').get('syn') if raw_response.get('verb').get('syn') is not None else []
        print vs
    if(raw_response.get('noun')):
        na = raw_response.get('noun').get('ant') if raw_response.get('noun').get('ant') is not None else []
        print na
        ns = raw_response.get('noun').get('syn') if raw_response.get('noun').get('syn') is not None else []
        print ns
    print '*************************************'
    flat_list = va + vs + na + ns
    print '*-----------------------------------*'
    return flat_list

def save_word(word, raw_response, collection):
    # print word
    print '======' + word + '======'
    flat_list = handle_next_level(raw_response)
    result = {
              "word": word,
              "response": raw_response,
              "utc": datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3],
              "flat_list": flat_list,
             }
    stored_result = mongo_corpus.db[collection].insert_one(result)
    # print raw_response
    print stored_result.inserted_id
    print raw_response
    print '------------------'
    return result

def get_word_or_words(word_length, api_key, words, collection):
    if api_key and words and len(words) == int(word_length):
        all_flat_lists = []
        # Level One
        for word in words:
            raw_response = get_single_word(api_key, word)
            data = save_word(word, raw_response, collection)
            print json.dumps(data.get('flat_list'))
            # TODO: Return just the flat list and use it as the next level
            all_flat_lists = all_flat_lists + data.get('flat_list')
        print all_flat_lists
        return all_flat_lists
    else:
        print 'MESSAGE: No valid input, sorry'
        return 'Error'

def get_two_levels(k, w, c):
    # get level one
    flat_list_one = get_word_or_words(len(w), k, w, c)
    # TODO: Return just the flat list and use it as the next level
    # get level two
    for words_of_one in flat_list_one:
        get_word_or_words(len(words_of_one), k, words_of_one, (c + '-order-two'))
    return 'Success'

'''
********************************************************************************

This is a way to keep all the corpus stuff in one file. I will refactor later.

======
This section is for views
======

********************************************************************************
'''

from flask import Blueprint
from flask import render_template, redirect, url_for, jsonify, request

import json

corpus = Blueprint('corpus', __name__)

'''
Flask views below as an endpoint
'''

@corpus.route('/')
def default():
    return 'Hello corpus_builder!'

'''
A human can build a corpus manulally by passing a word list of unknown count
to the method:

unknown_count_word_view()

Make sure to pass three paramaters via a form -- (api_key for BHT, words list, and a collection name)
Then the human can use the flattened list of each of the lists created to generate the next level.
This should also be automated. :-)
'''

# TODO: This should also be automated. :-)
@corpus.route('/x', methods=['GET', 'POST'])
def unknown_count_word_view():
    r = request.get_json()
    k = r.get('key')
    w = r.get('words')
    c = r.get('collection')
    return get_word_or_words(len(w), k, w, c)

@corpus.route('/y', methods=['GET', 'POST'])
def unknown_count_word_view_with_level():
    r = request.get_json()
    k = r.get('key')
    w = r.get('words')
    c = r.get('collection')
    return get_two_levels(len(w), k, w, c)

@corpus.route('/1', methods=['GET', 'POST'])
def one_word_view():
    r = request.get_json()
    k = r.get('key')
    w = r.get('words')
    c = r.get('collection')
    return get_word_or_words(1, k, w, c)

@corpus.route('/10', methods=['GET', 'POST'])
def ten_words_view():
    r = request.get_json()
    k = r.get('key')
    w = r.get('words')
    c = r.get('collection')
    return get_word_or_words(10, k, w, c)

@corpus.route('/100', methods=['GET', 'POST'])
def hundred_words_view(words=None):
    r = request.get_json()
    k = r.get('key')
    w = r.get('words')
    c = r.get('collection')
    return get_word_or_words(100, k, w, c)

@corpus.route('/500', methods=['GET', 'POST'])
def five_hundred_words_view(words=None):
    r = request.get_json()
    k = r.get('key')
    w = r.get('words')
    c = r.get('collection')
    return get_word_or_words(500, k, w, c)
<commit_msg>adding lists -2<commit_after>from flask import jsonify
import requests
from datetime import datetime

'''
********************************************************************************

This is a way to keep all the corpus stuff in one file. I will refactor later.

======
This section is for databases
======

********************************************************************************
'''

from app import app
from flask.ext.pymongo import PyMongo

app.config['MONGOCORPUS_DBNAME'] = 'affect-corpus'
mongo_corpus = PyMongo(app, config_prefix='MONGOCORPUS')

'''
********************************************************************************

This is a way to keep all the corpus stuff in one file. I will refactor later.

======
This section is for controllers
======

********************************************************************************
'''

'''
The aim of corpus_builder.py is to build a corpus of synonyms around a primary word.

i.e.
Affect
  it has synonyms
     those synonyms have synonyms
       and after the 4th level deep is likely where we don't care.

Moreover, the words will be stored as follows:

{
  "word": <added by what word>
  "response": <json response from bighugelabs>
  "utc": <utc date>
  "flat-list": <list of all words (syn/ant of verb/noun) for this word>
}

This gets stored in a mongo database. Collections are named after the inital parent.
In this case that parent is 'Affect'. To be clear, this is probably not the best way
to build a corpus, but it is a quick and effective way for getting started.
'''

def verify_bhl_api(api_key):
    r = requests.get('http://words.bighugelabs.com/api/2/' + api_key + '/affect/json')
    if(r.raise_for_status()):
        return 'error'
    else:
        return jsonify(r.json())

def get_single_word(api_key, word):
    r = requests.get('http://words.bighugelabs.com/api/2/' + api_key + '/' + word + '/json')
    if(r.raise_for_status()):
        return 'error'
    else:
        return r.json()

def handle_next_level(raw_response):
    print '*************************************'
    print 'next-level'
    print '*************************************'
    va = []
    vs = []
    na = []
    ns = []
    if(raw_response.get('verb')):
        va = raw_response.get('verb').get('ant') if raw_response.get('verb').get('ant') is not None else []
        print va
        vs = raw_response.get('verb').get('syn') if raw_response.get('verb').get('syn') is not None else []
        print vs
    if(raw_response.get('noun')):
        na = raw_response.get('noun').get('ant') if raw_response.get('noun').get('ant') is not None else []
        print na
        ns = raw_response.get('noun').get('syn') if raw_response.get('noun').get('syn') is not None else []
        print ns
    print '*************************************'
    flat_list = va + vs + na + ns
    print '*-----------------------------------*'
    return flat_list

def save_word(word, raw_response, collection):
    # print word
    print '======' + word + '======'
    flat_list = handle_next_level(raw_response)
    result = {
              "word": word,
              "response": raw_response,
              "utc": datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3],
              "flat_list": flat_list,
             }
    stored_result = mongo_corpus.db[collection].insert_one(result)
    # print raw_response
    print stored_result.inserted_id
    print raw_response
    print '------------------'
    return result

def get_word_or_words(word_length, api_key, words, collection):
    if api_key and words and len(words) == int(word_length):
        all_flat_lists = []
        # Level One
        for word in words:
            raw_response = get_single_word(api_key, word)
            data = save_word(word, raw_response, collection)
            print json.dumps(data.get('flat_list'))
            # TODO: Return just the flat list and use it as the next level
            all_flat_lists = all_flat_lists + data.get('flat_list')
        print all_flat_lists
        return all_flat_lists
    else:
        print 'MESSAGE: No valid input, sorry'
        return 'Error'

def get_two_levels(k, w, c):
    # get level one
    flat_list_one = get_word_or_words(len(w), k, w, c)
    # TODO: Return just the flat list and use it as the next level
    # get level two
    for words_of_one in flat_list_one:
        get_word_or_words(len(words_of_one), k, words_of_one, (c + '-order-two'))
    return 'Success'

'''
********************************************************************************

This is a way to keep all the corpus stuff in one file. I will refactor later.

======
This section is for views
======

********************************************************************************
'''

from flask import Blueprint
from flask import render_template, redirect, url_for, jsonify, request

import json

corpus = Blueprint('corpus', __name__)

'''
Flask views below as an endpoint
'''

@corpus.route('/')
def default():
    return 'Hello corpus_builder!'

'''
A human can build a corpus manulally by passing a word list of unknown count
to the method:

unknown_count_word_view()

Make sure to pass three paramaters via a form -- (api_key for BHT, words list, and a collection name)
Then the human can use the flattened list of each of the lists created to generate the next level.
This should also be automated. :-)
'''

# TODO: This should also be automated. :-)
@corpus.route('/x', methods=['GET', 'POST'])
def unknown_count_word_view():
    r = request.get_json()
    k = r.get('key')
    w = r.get('words')
    c = r.get('collection')
    return get_word_or_words(len(w), k, w, c)

@corpus.route('/y', methods=['GET', 'POST'])
def unknown_count_word_view_with_level():
    r = request.get_json()
    k = r.get('key')
    w = r.get('words')
    c = r.get('collection')
    return get_two_levels(k, w, c)

@corpus.route('/1', methods=['GET', 'POST'])
def one_word_view():
    r = request.get_json()
    k = r.get('key')
    w = r.get('words')
    c = r.get('collection')
    return get_word_or_words(1, k, w, c)

@corpus.route('/10', methods=['GET', 'POST'])
def ten_words_view():
    r = request.get_json()
    k = r.get('key')
    w = r.get('words')
    c = r.get('collection')
    return get_word_or_words(10, k, w, c)

@corpus.route('/100', methods=['GET', 'POST'])
def hundred_words_view(words=None):
    r = request.get_json()
    k = r.get('key')
    w = r.get('words')
    c = r.get('collection')
    return get_word_or_words(100, k, w, c)

@corpus.route('/500', methods=['GET', 'POST'])
def five_hundred_words_view(words=None):
    r = request.get_json()
    k = r.get('key')
    w = r.get('words')
    c = r.get('collection')
    return get_word_or_words(500, k, w, c)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

# This file is part of Workout Manager.
#
# Workout Manager is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Workout Manager is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
import logging
import json

from django import forms
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.shortcuts import get_object_or_404
from django.http import HttpResponse
from django.http import HttpResponseRedirect
from django.http import HttpResponseForbidden
from django.core.context_processors import csrf
from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse_lazy
from django.contrib.auth.decorators import login_required
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy

from django.views.generic import DeleteView
from django.views.generic import CreateView
from django.views.generic import UpdateView
from django.views.generic import ListView

from wger.nutrition.models import NutritionPlan
from wger.nutrition.models import Meal
from wger.nutrition.models import MealItem
from wger.nutrition.models import Ingredient
from wger.nutrition.models import WeightUnit
from wger.nutrition.models import IngredientWeightUnit
from wger.nutrition.models import MEALITEM_WEIGHT_GRAM
from wger.nutrition.models import MEALITEM_WEIGHT_UNIT

from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.pagesizes import A4, cm
from reportlab.platypus import Paragraph, SimpleDocTemplate, Table
from reportlab.lib import colors

from wger.manager.utils import load_language
from wger.manager.utils import load_ingredient_languages

from wger.workout_manager import get_version
from wger.workout_manager.generic_views import YamlFormMixin
from wger.workout_manager.generic_views import YamlDeleteMixin
from wger.workout_manager import helpers

logger = logging.getLogger('workout_manager.custom')

# ************************
# Meal ingredient functions
# ************************
class MealItemForm(forms.ModelForm):
    weight_unit = forms.ModelChoiceField(queryset=IngredientWeightUnit.objects.none(),
                                         empty_label="g",
                                         required=False)

    class Meta:
        model = MealItem
        exclude = ('meal', 'order', )

    def __init__(self, *args, **kwargs):
        super(MealItemForm, self).__init__(*args, **kwargs)
        try:
            ingredient_id = args[0]['ingredient']
        except IndexError:
            ingredient_id = None

        if ingredient_id:
            self.fields['weight_unit'].queryset = \
                IngredientWeightUnit.objects.filter(ingredient_id=ingredient_id)

@login_required
def delete_meal_item(request, item_id):
    '''
    Deletes the meal ingredient with the given ID
    '''

    # Load the item
    item = get_object_or_404(MealItem, pk=item_id)
    plan = item.meal.plan

    # Only delete if the user is the owner
    if plan.user == request.user:
        item.delete()
        return HttpResponseRedirect(reverse('wger.nutrition.views.plan.view',
                                            kwargs={'id': plan.id}))
    else:
        return HttpResponseForbidden()

@login_required
def edit_meal_item(request, id, meal_id, item_id=None):
    '''
    Form to add a meal to a plan
    '''
    template_data = {}

    # Load the plan
    plan = get_object_or_404(NutritionPlan, pk=id, user=request.user)
    template_data['plan'] = plan

    # Load the meal
    meal = get_object_or_404(Meal, pk=meal_id)
    template_data['meal'] = meal

    if meal.plan != plan:
        return HttpResponseForbidden()

    # Load the meal item
    # If the object is new, we will receice a 'None' (string) as the ID
    # from the template, so we check for it (ValueError) and for an actual
    # None (TypeError)
    try:
        int(item_id)
        meal_item = get_object_or_404(MealItem, pk=item_id)
        template_data['ingredient'] = meal_item.ingredient.id
        template_data['ingredient_searchfield'] = meal_item.ingredient.name

    except ValueError, TypeError:
        meal_item = MealItem()

    template_data['meal_item'] = meal_item

    # Check that javascript is activated This is used to hide the drop down list with the
    # ingredients and use the autocompleter version instead. This is not only nicer but also much
    # faster as the ingredient list from USDA is many thosand entries long.
    js_active = request.GET.get('js', False)
    template_data['js_active'] = js_active

    # Process request
    if request.method == 'POST':
        meal_form = MealItemForm(request.POST, instance=meal_item)

        # Pass the ingredient ID back to the template, this is originally set by the JQuery
        # autocompleter, in case of errors (max. gramms reached), we need to set the ID manually
        # so the user can simply submit again.
        template_data['ingredient'] = request.POST.get('ingredient', '')

        template_data['ingredient_searchfield'] = request.POST.get('ingredient_searchfield', '')

        # If the data is valid, save and redirect
        if meal_form.is_valid():
            meal_item = meal_form.save(commit=False)
            meal_item.meal = meal
            meal_item.order = 1
            meal_item.save()

            return HttpResponseRedirect(reverse('wger.nutrition.views.plan.view',
                                                kwargs={'id': id}))
        #else:
        #    logger.debug(meal_form.errors)

    else:
        meal_form = MealItemForm(instance=meal_item)
    template_data['form'] = meal_form

    return render_to_response('edit_meal_item.html',
                              template_data,
                              context_instance=RequestContext(request))

# ************************
# Ingredient functions
# ************************
def ingredient_overview(request):
    '''
    Show an overview of all ingredients
    '''

    template_data = {}

    # Filter the ingredients the user will see by its language
    # (the user can also want to see ingredients in English, see load_ingredient_languages)
    languages = load_ingredient_languages(request)

    # Load the ingredients and paginate it
    ingredients_list = Ingredient.objects.filter(language__in=languages)

    pagination = helpers.pagination(ingredients_list, request.GET.get('page'))
    template_data['page_range'] = pagination['page_range']
    template_data['ingredients'] = pagination['page']

    return render_to_response('ingredient_overview.html',
                              template_data,
                              context_instance=RequestContext(request))

def ingredient_view(request, id, slug=None):
    template_data = {}

    ingredient = get_object_or_404(Ingredient, pk=id)
    template_data['ingredient'] = ingredient

    return render_to_response('view_ingredient.html',
                              template_data,
                              context_instance=RequestContext(request))

class IngredientForm(forms.ModelForm):
    class Meta:
        model = Ingredient
        exclude = ('language',)

class IngredientDeleteView(YamlDeleteMixin, DeleteView):
    '''
    Generic view to delete an existing ingredient
    '''

    model = Ingredient
    template_name = 'delete.html'
    success_url = reverse_lazy('wger.nutrition.views.ingredient.ingredient_overview')

    # Send some additional data to the template
    def get_context_data(self, **kwargs):
        context = super(IngredientDeleteView, self).get_context_data(**kwargs)

        context['title'] = _('Delete %s?') % self.object.name
        context['form_action'] = reverse('ingredient-delete', kwargs={'pk': self.kwargs['pk']})

        return context

class IngredientEditView(YamlFormMixin, UpdateView):
    '''
    Generic view to update an existing ingredient
    '''

    model = Ingredient
    form_class = IngredientForm
    title = ugettext_lazy('Add a new ingredient')
    form_action_urlname = 'ingredient-edit'

class IngredientCreateView(YamlFormMixin, CreateView):
    '''
    Generic view to add a new ingredient
    '''

    model = Ingredient
    form_class = IngredientForm
    title = ugettext_lazy('Add a new ingredient')
    form_action = reverse_lazy('ingredient-add')

    def form_valid(self, form):
        form.instance.language = load_language()
        return super(IngredientCreateView, self).form_valid(form)

def ingredient_search(request):
    '''
    Search for an exercise, return the result as a JSON list or as HTML page, depending on how
    the function was invoked
    '''

    # Filter the ingredients the user will see by its language
    # (the user can also want to see ingredients in English, see load_ingredient_languages)
    languages = load_ingredient_languages(request)

    # Perform the search
    q = request.GET.get('term', '')
    ingredients = Ingredient.objects.filter(name__icontains=q, language__in=languages)

    # AJAX-request, this comes from the autocompleter. Create a list and send it back as JSON
    if request.is_ajax():

        results = []
        for ingredient in ingredients:
            ingredient_json = {}
            ingredient_json['id'] = ingredient.id
            ingredient_json['name'] = ingredient.name
            ingredient_json['value'] = ingredient.name
            results.append(ingredient_json)
        data = json.dumps(results)

        # Return the results to the server
        mimetype = 'application/json'
        return HttpResponse(data, mimetype)

    # Usual search (perhaps JS disabled), present the results as normal HTML page
    else:
        template_data = {}
        template_data.update(csrf(request))
        template_data['ingredients'] = ingredients
        template_data['search_term'] = q
        return render_to_response('ingredient_search.html',
                                  template_data,
                                  context_instance=RequestContext(request))

@login_required
def ajax_get_ingredient_units(request, pk):
    '''
    Fetches the available ingredient units
    '''

    units = IngredientWeightUnit.objects.filter(ingredient_id=pk)
    result = []
    for unit in units:
        result.append({'id': unit.id, 'name': unit.unit.name, 'amount': unit.amount})

    return HttpResponse(json.dumps(result, cls=helpers.DecimalJsonEncoder),
                        'application/json')
<commit_msg>Fix some problems when editing an existing meal item<commit_after># -*- coding: utf-8 -*-

# This file is part of Workout Manager.
#
# Workout Manager is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Workout Manager is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
import logging
import json

from django import forms
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.shortcuts import get_object_or_404
from django.http import HttpResponse
from django.http import HttpResponseRedirect
from django.http import HttpResponseForbidden
from django.core.context_processors import csrf
from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse_lazy
from django.contrib.auth.decorators import login_required
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy

from django.views.generic import DeleteView
from django.views.generic import CreateView
from django.views.generic import UpdateView
from django.views.generic import ListView

from wger.nutrition.models import NutritionPlan
from wger.nutrition.models import Meal
from wger.nutrition.models import MealItem
from wger.nutrition.models import Ingredient
from wger.nutrition.models import WeightUnit
from wger.nutrition.models import IngredientWeightUnit
from wger.nutrition.models import MEALITEM_WEIGHT_GRAM
from wger.nutrition.models import MEALITEM_WEIGHT_UNIT

from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.pagesizes import A4, cm
from reportlab.platypus import Paragraph, SimpleDocTemplate, Table
from reportlab.lib import colors

from wger.manager.utils import load_language
from wger.manager.utils import load_ingredient_languages

from wger.workout_manager import get_version
from wger.workout_manager.generic_views import YamlFormMixin
from wger.workout_manager.generic_views import YamlDeleteMixin
from wger.workout_manager import helpers

logger = logging.getLogger('workout_manager.custom')

# ************************
# Meal ingredient functions
# ************************
class MealItemForm(forms.ModelForm):
    weight_unit = forms.ModelChoiceField(queryset=IngredientWeightUnit.objects.none(),
                                         empty_label="g",
                                         required=False)

    class Meta:
        model = MealItem
        exclude = ('meal', 'order', )

    def __init__(self, *args, **kwargs):
        super(MealItemForm, self).__init__(*args, **kwargs)

        # Get the ingredient_id
        # Instance, we are editing an existing mealitem
        if kwargs['instance']:
            ingredient_id = kwargs['instance'].ingredient_id

        # There is data in args (data from POST): either new or editing
        try:
            ingredient_id = args[0]['ingredient']
        except IndexError:
            if not ingredient_id:
                ingredient_id = None

        if ingredient_id:
            self.fields['weight_unit'].queryset = \
                IngredientWeightUnit.objects.filter(ingredient_id=ingredient_id)

@login_required
def delete_meal_item(request, item_id):
    '''
    Deletes the meal ingredient with the given ID
    '''

    # Load the item
    item = get_object_or_404(MealItem, pk=item_id)
    plan = item.meal.plan

    # Only delete if the user is the owner
    if plan.user == request.user:
        item.delete()
        return HttpResponseRedirect(reverse('wger.nutrition.views.plan.view',
                                            kwargs={'id': plan.id}))
    else:
        return HttpResponseForbidden()

@login_required
def edit_meal_item(request, id, meal_id, item_id=None):
    '''
    Form to add a meal to a plan
    '''
    template_data = {}

    # Load the plan
    plan = get_object_or_404(NutritionPlan, pk=id, user=request.user)
    template_data['plan'] = plan

    # Load the meal
    meal = get_object_or_404(Meal, pk=meal_id)
    template_data['meal'] = meal

    if meal.plan != plan:
        return HttpResponseForbidden()

    # Load the meal item
    # If the object is new, we will receice a 'None' (string) as the ID
    # from the template, so we check for it (ValueError) and for an actual
    # None (TypeError)
    try:
        int(item_id)
        meal_item = get_object_or_404(MealItem, pk=item_id)
        template_data['ingredient'] = meal_item.ingredient.id
        template_data['ingredient_searchfield'] = meal_item.ingredient.name

    except ValueError, TypeError:
        meal_item = MealItem()

    template_data['meal_item'] = meal_item

    # Check that javascript is activated This is used to hide the drop down list with the
    # ingredients and use the autocompleter version instead. This is not only nicer but also much
    # faster as the ingredient list from USDA is many thosand entries long.
    js_active = request.GET.get('js', False)
    template_data['js_active'] = js_active

    # Process request
    if request.method == 'POST':
        meal_form = MealItemForm(request.POST, instance=meal_item)

        # Pass the ingredient ID back to the template, this is originally set by the JQuery
        # autocompleter, in case of errors (max. gramms reached), we need to set the ID manually
        # so the user can simply submit again.
        template_data['ingredient'] = request.POST.get('ingredient', '')

        template_data['ingredient_searchfield'] = request.POST.get('ingredient_searchfield', '')

        # If the data is valid, save and redirect
        if meal_form.is_valid():
            meal_item = meal_form.save(commit=False)
            meal_item.meal = meal
            meal_item.order = 1
            meal_item.save()

            return HttpResponseRedirect(reverse('wger.nutrition.views.plan.view',
                                                kwargs={'id': id}))
        #else:
        #    logger.debug(meal_form.errors)

    else:
        meal_form = MealItemForm(instance=meal_item)
    template_data['form'] = meal_form

    return render_to_response('edit_meal_item.html',
                              template_data,
                              context_instance=RequestContext(request))

# ************************
# Ingredient functions
# ************************
def ingredient_overview(request):
    '''
    Show an overview of all ingredients
    '''

    template_data = {}

    # Filter the ingredients the user will see by its language
    # (the user can also want to see ingredients in English, see load_ingredient_languages)
    languages = load_ingredient_languages(request)

    # Load the ingredients and paginate it
    ingredients_list = Ingredient.objects.filter(language__in=languages)

    pagination = helpers.pagination(ingredients_list, request.GET.get('page'))
    template_data['page_range'] = pagination['page_range']
    template_data['ingredients'] = pagination['page']

    return render_to_response('ingredient_overview.html',
                              template_data,
                              context_instance=RequestContext(request))

def ingredient_view(request, id, slug=None):
    template_data = {}

    ingredient = get_object_or_404(Ingredient, pk=id)
    template_data['ingredient'] = ingredient

    return render_to_response('view_ingredient.html',
                              template_data,
                              context_instance=RequestContext(request))

class IngredientForm(forms.ModelForm):
    class Meta:
        model = Ingredient
        exclude = ('language',)

class IngredientDeleteView(YamlDeleteMixin, DeleteView):
    '''
    Generic view to delete an existing ingredient
    '''

    model = Ingredient
    template_name = 'delete.html'
    success_url = reverse_lazy('wger.nutrition.views.ingredient.ingredient_overview')

    # Send some additional data to the template
    def get_context_data(self, **kwargs):
        context = super(IngredientDeleteView, self).get_context_data(**kwargs)

        context['title'] = _('Delete %s?') % self.object.name
        context['form_action'] = reverse('ingredient-delete', kwargs={'pk': self.kwargs['pk']})

        return context

class IngredientEditView(YamlFormMixin, UpdateView):
    '''
    Generic view to update an existing ingredient
    '''

    model = Ingredient
    form_class = IngredientForm
    title = ugettext_lazy('Add a new ingredient')
    form_action_urlname = 'ingredient-edit'

class IngredientCreateView(YamlFormMixin, CreateView):
    '''
    Generic view to add a new ingredient
    '''

    model = Ingredient
    form_class = IngredientForm
    title = ugettext_lazy('Add a new ingredient')
    form_action = reverse_lazy('ingredient-add')

    def form_valid(self, form):
        form.instance.language = load_language()
        return super(IngredientCreateView, self).form_valid(form)

def ingredient_search(request):
    '''
    Search for an exercise, return the result as a JSON list or as HTML page, depending on how
    the function was invoked
    '''

    # Filter the ingredients the user will see by its language
    # (the user can also want to see ingredients in English, see load_ingredient_languages)
    languages = load_ingredient_languages(request)

    # Perform the search
    q = request.GET.get('term', '')
    ingredients = Ingredient.objects.filter(name__icontains=q, language__in=languages)

    # AJAX-request, this comes from the autocompleter. Create a list and send it back as JSON
    if request.is_ajax():

        results = []
        for ingredient in ingredients:
            ingredient_json = {}
            ingredient_json['id'] = ingredient.id
            ingredient_json['name'] = ingredient.name
            ingredient_json['value'] = ingredient.name
            results.append(ingredient_json)
        data = json.dumps(results)

        # Return the results to the server
        mimetype = 'application/json'
        return HttpResponse(data, mimetype)

    # Usual search (perhaps JS disabled), present the results as normal HTML page
    else:
        template_data = {}
        template_data.update(csrf(request))
        template_data['ingredients'] = ingredients
        template_data['search_term'] = q
        return render_to_response('ingredient_search.html',
                                  template_data,
                                  context_instance=RequestContext(request))

@login_required
def ajax_get_ingredient_units(request, pk):
    '''
    Fetches the available ingredient units
    '''

    units = IngredientWeightUnit.objects.filter(ingredient_id=pk)
    result = []
    for unit in units:
        result.append({'id': unit.id, 'name': unit.unit.name, 'amount': unit.amount})

    return HttpResponse(json.dumps(result, cls=helpers.DecimalJsonEncoder),
                        'application/json')
<|endoftext|>