<commit_before># Create your views here.
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, render_to_response
from django.template import RequestContext
from images.models import Alignment, Original_nrrd, comp_orien, conv_orien, Upload, Mask_original, Mask_aligned
from system.models import Setting, Server, Template
from django.views import generic
from socket import gethostname
from django.db.models import Q
from django.contrib.auth.models import User

from images.forms import UploadForm

import gc

from django.contrib.admin.models import LogEntry, ADDITION, CHANGE
from django.contrib.contenttypes.models import ContentType

host = gethostname()

tempfolder = str(Server.objects.filter(host_name=host).values('temp_dir')[0]['temp_dir'])
uploaddir = str(Server.objects.filter(host_name=host).values('upload_dir')[0]['upload_dir'])

def upload_admin_log(request, uploadimage):
    """Log changes to Admin log."""
    change_message = "Uploaded image %s with orientation %s using %s" % (uploadimage.name, uploadimage.orig_orientation, uploadimage.settings)
    action_flag = ADDITION
    try:
      LogEntry.objects.log_action(
        user_id = request.user.id,
        content_type_id = ContentType.objects.get_for_model(Alignment).pk,
        object_id = uploadimage.id,
        object_repr = unicode(uploadimage.name),
        change_message = unicode(change_message),
        action_flag = action_flag,
        )
    except:
        print "Failed to log action."
        print uploadimage

def index(request):
    if not request.user == '':
      cu = int(User.objects.filter(username=request.user).values('id')[0]['id'])
      if cu == 1:
        align_list = Alignment.objects.order_by('alignment_stage', 'name')
        context = {'align_list': align_list}
      else:
        if Alignment.objects.filter(Q(user=cu) | Q(user=0)).count() > 0:
          align_list = Alignment.objects.filter(Q(user=cu) | Q(user=0)).order_by('alignment_stage', 'name')
          context = {'align_list': align_list}
        else:
          context = {}
      return render(request, 'index.html', context)
    else:
      return HttpResponseRedirect('/admin')

def detail(request, image_id):
    if not request.user == '':
      align_list = Alignment.objects.get(id=image_id)
      context = {'record': align_list}
      return render(request, 'details.html', context)
    else:
      return HttpResponseRedirect('/admin')

def handle_uploaded_file(ufile, dest):
    from django.core.files.storage import default_storage
    from django.core.files.base import ContentFile
    path = default_storage.save(dest, ContentFile(ufile.read()))
    return path
    #
    # dest = open(dest, 'wb+')
    # dest.write(ufile)
    # dest.close()

def upload(request):
    from django.contrib import messages
    from django.conf import settings as st
    import os, stat, sys
    # Handle file upload
    if request.method == 'POST':
        form = UploadForm(request.POST, request.FILES)
        if form.is_valid():
            file = str(request.user) + '-' + str(request.FILES['file'])
            setting = Setting.objects.get(id=int(request.POST['settings']))
            if '.tif' in file or '.lsm' in file:
              # file = str(st.MEDIA_URL) + file
              file = handle_uploaded_file(request.FILES['file'], dest=file)
              name = str(os.path.splitext(os.path.basename(file))[0])
              ext = str(os.path.splitext(os.path.basename(file))[1])
              folder = str(st.MEDIA_ROOT)
              ori = str(request.POST['orientation'])
              cu = User.objects.get(username=request.user)
              newimage = Alignment(name=name, orig_orientation=ori, settings=setting, original_path=folder, original_ext=ext, alignment_stage=1, last_host=host, loading_host=host, user=cu)
              newimage.save()
              try:
                os.chmod(folder + os.path.sep + file, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
              except:
                pass
              upload_admin_log(request, newimage)
              return HttpResponseRedirect('/admin/images/alignment/')
            else:
              messages.error(request, 'Not a LSM or tif file')
              return HttpResponseRedirect('/admin/images/alignment/')
        # else:
        # messages.error(request, 'Invalid data')
    else:
        form = UploadForm() # A empty, unbound form

    # Render list page with the documents and the form
    align_list = Alignment.objects.all().order_by('alignment_stage', 'name')
    context = {'align_list': align_list, 'form': form}
    return render_to_response('index.html', context, context_instance=RequestContext(request))

# def showStaticImage(request):
#     """ Simply return a static image as a png """
#     imagePath = "images/default.png"
#     from PIL import Image
#     Image.init()
#     i = Image.open(imagePath)
#     response = HttpResponse(mimetype='image/png')
#     i.save(response,'PNG')
#     return response

def plotResults(request, image_id):
    import os
    import tempfile
    os.environ['MPLCONFIGDIR'] = tempfile.mkdtemp()
    import matplotlib
    from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
    from matplotlib.figure import Figure
    from matplotlib.dates import DateFormatter
    import numpy as np
    fig = Figure()
    ax=fig.add_subplot(3,1,1)
    if Original_nrrd.objects.filter(image=image_id).count() > 0:
      records = Original_nrrd.objects.filter(image=image_id).values()
      chanCol = ['red','green','blue']
      for record in records:
        i = int(record['channel'])
        ax=fig.add_subplot(3,1,i)
        hist = list(record['pre_hist'])
        k = range(0,len(hist))
        v = [long(y) for y in hist]
        m = int(record['new_min'])
        M = int(record['new_max'])
        ax.fill([m,M,M,m], [np.min(v),np.min(v),np.max(v),np.max(v)], 'cyan', fill=True, hatch='/', edgecolor="grey")
        # ax.broken_barh([(m, (M-m))] , (ax.yaxis, (np.max(v)-np.min(v))), facecolors='grey')
        ax.bar(k, v, color=chanCol[i-1])#, log=True

        ax.set_xlim(0,260)
        ax.set_ylim(0,np.max(v))
        ax.set_yscale('symlog', linthreshx=np.average(v))
        ax.grid(True)
        gc.collect()
        ax.set_title('Ch' + str(i) + ' histogram', fontsize=14, color=chanCol[i-1])
    else:
      fig.text(0.3,0.5,'No Data Found!', fontsize=32)
    fig.text(0.5, 0.015, 'Intensity', ha='center', va='center')
    fig.text(0.015, 0.5, 'Count (log)', ha='center', va='center', rotation='vertical')
    fig.tight_layout()
    canvas = FigureCanvas(fig)
    response = HttpResponse(content_type='image/png')
    gc.collect()
    canvas.print_png(response)
    return response

def opositeOr(position):
    Or = {'R':'L','L':'R','P':'A','A':'P','S':'I','I':'S'}
    return Or[position]

def plotNrrd(request, image_id, image_type):
    import os
    import matplotlib
    from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
    from matplotlib.figure import Figure
    from matplotlib.dates import DateFormatter
    import nrrd
    import numpy as np
    import matplotlib.image as mpimg
    import matplotlib.pyplot as plt
    from system.models import checkDir, Server

    labels = False
    Dtemp = False

    file = 'default.png'
    subtext = ''
    orient = 'LPS'
    fsize = 18
    if '_file' in image_type:
      record = checkDir(Alignment.objects.get(id=image_id))
      if Original_nrrd.objects.filter(image=image_id, channel=int(image_type.replace('Ch','').replace('_file',''))).count() > 0:
        temprec = Original_nrrd.objects.get(image=image_id, channel=int(image_type.replace('Ch','').replace('_file','')))
        file = tempfolder + str(temprec.file)
        del temprec
        orient = str(record.settings.template.orientation)
        subtext = 'Orientation: ' + str(comp_orien[orient]) + ' (' + orient + ')'
    elif 'temp_initial_nrrd' in image_type:
      record = checkDir(Alignment.objects.get(id=image_id))
      file = tempfolder + str(record.temp_initial_nrrd)
      orient = str(record.settings.template.orientation)
      subtext = 'Orientation: ' + str(comp_orien[orient]) + ' (' + orient + ')'
    elif 'aligned_bg' in image_type:
      record = checkDir(Alignment.objects.get(id=image_id))
      file = tempfolder + str(record.aligned_bg)
      orient = str(record.settings.template.orientation)
      subtext = 'Orientation: ' + str(comp_orien[orient]) + ' (' + orient + ')'
    elif 'aligned_sg' in image_type:
      record = checkDir(Alignment.objects.get(id=image_id))
      file = tempfolder + str(record.aligned_sg)
      orient = str(record.settings.template.orientation)
      subtext = 'Orientation: ' + str(comp_orien[orient]) + ' (' + orient + ')'
    elif 'aligned_ac1' in image_type:
      record = checkDir(Alignment.objects.get(id=image_id))
      file = tempfolder + str(record.aligned_ac1)
      orient = str(record.settings.template.orientation)
      subtext = 'Orientation: ' + str(comp_orien[orient]) + ' (' + orient + ')'
    elif 'template' in image_type:
      record = Template.objects.get(id=image_id)
      temprec = Server.objects.get(host_name=host)
      file = str(temprec.template_dir) + str(record.file)
      orient = str(record.orientation)
      subtext = 'Orientation: ' + str(comp_orien[orient]) + ' (' + orient + ')'
      del temprec
      fsize = 12
      Dtemp = True
    elif 'mask_original' in image_type:
      record = Mask_original.objects.get(id=image_id)
      file = tempfolder + str(record.image.file).replace('.nrrd','-objMask.nrrd')
      orient = str(record.image.image.settings.template.orientation)
      subtext = 'Detected objects'
      labels = True
    elif 'mask_aligned_bg' in image_type:
      record = Mask_aligned.objects.get(id=image_id)
      # temprec = Original_nrrd.objects.get(id=record.image_id)
      file = tempfolder + str(record.image.aligned_bg).replace('.nrrd','-objMask.nrrd')
      orient = str(record.image.settings.template.orientation)
      subtext = 'Detected objects'
      labels = True
    elif 'mask_aligned_sg' in image_type:
      record = Mask_aligned.objects.get(id=image_id)
      # temprec = Original_nrrd.objects.get(id=record.image_id)
      file = tempfolder + str(record.image.aligned_sg).replace('.nrrd','-objMask.nrrd')
      orient = str(record.image.settings.template.orientation)
      subtext = 'Detected objects'
      labels = True
    elif 'mask_aligned_ac1' in image_type:
      record = Mask_aligned.objects.get(id=image_id)
      # temprec = Original_nrrd.objects.get(id=record.image_id)
      file = tempfolder + str(record.image.aligned_ac1).replace('.nrrd','-objMask.nrrd')
      orient = str(record.image.settings.template.orientation)
      subtext = 'Detected objects'
      labels = True
    else:
      file = '/static/default.png'
    if os.path.isfile(file):
      ori = list(orient)
      data, header = nrrd.read(file)
      data = data.swapaxes(0,1)
      if labels:
        ulab = np.unique(data)
      zdata = np.max(data, axis=2)
      xdata = np.max(data, axis=1)
      del data
      gc.collect()
      fig = Figure()
      ax=fig.add_subplot(1,2,1)
      imgplot = ax.imshow(xdata)
      imgplot.set_cmap('spectral')
      ax.set_title('Max proj. (X)')
      ax.set_xlabel('Z [' + str(opositeOr(ori[2])) + '->' + str(ori[2]) + '] (Px)', fontsize=10)
      ax.set_ylabel('Y [' + str(ori[1]) + '<-' + str(opositeOr(ori[1])) + '] (Px)')
      ax.yaxis.set_ticks(np.round(np.linspace(ax.get_ylim()[0],ax.get_ylim()[1],3)))
      ax.xaxis.set_ticks(np.round(np.linspace(ax.get_xlim()[0],ax.get_xlim()[1],3)))
      ax=fig.add_subplot(1,2,2)
      imgplot = ax.imshow(zdata)
      imgplot.set_cmap('spectral')

      if labels:
        fig.colorbar(imgplot, ax=ax, aspect=7.5, ticks=ulab)
        fig.suptitle('Detected objects')
      else:
        fig.colorbar(imgplot, ax=ax, aspect=7.5)
        if Dtemp:
          fig.suptitle(str(image_type).replace('temp_initial_nrrd', 'after initial alignment').replace('_',' ').replace('file', 'after preprocessing').title().replace('Template',str(record)).replace('Bg','Background').replace('Sg','Signal').replace('Ac1','Additional Channel 1'), fontsize=fsize)
        else:
          fig.suptitle(str(image_type).replace('temp_initial_nrrd', 'after initial alignment').replace('_',' ').replace('file', 'after preprocessing').title().replace('Template',str(record.settings.template)).replace('Bg','Background').replace('Sg','Signal').replace('Ac1','Additional Channel 1'), fontsize=fsize)
      del xdata, zdata
      gc.collect()
      ax.set_title('Max proj. (Z)')
      ax.set_xlabel('X [' + str(opositeOr(ori[0])) + '->' + str(ori[0]) + '] (Px)')
      ax.set_ylabel('Y [' + str(ori[1]) + '<-' + str(opositeOr(ori[1])) + '] (Px)')
      ax.yaxis.set_ticks(np.round(np.linspace(ax.get_ylim()[0],ax.get_ylim()[1],3)))
      ax.xaxis.set_ticks(np.round(np.linspace(ax.get_xlim()[0],ax.get_xlim()[1],3)))
      fig.text(0.3,0.005,subtext)
      # fig.tight_layout()
      canvas = FigureCanvas(fig)
      response = HttpResponse(content_type='image/png')

      canvas.print_png(response)
      gc.collect()
      return response
    else:
      fig = Figure()
      canvas = FigureCanvas(fig)
      ax=fig.add_subplot(1,1,1)
      ax.set_title('No Image')
      ax.set_xlabel(file, fontsize=8)
      fig.text(0.3,0.5,'No Data Found!', fontsize=32)
      response = HttpResponse(content_type='image/png')
      canvas.print_png(response)
      gc.collect()
      return response
<commit_msg>image fix<commit_after># Create your views here.
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, render_to_response
from django.template import RequestContext
from images.models import Alignment, Original_nrrd, comp_orien, conv_orien, Upload, Mask_original, Mask_aligned
from system.models import Setting, Server, Template
from django.views import generic
from socket import gethostname
from django.db.models import Q
from django.contrib.auth.models import User

from images.forms import UploadForm

import gc

from django.contrib.admin.models import LogEntry, ADDITION, CHANGE
from django.contrib.contenttypes.models import ContentType

host = gethostname()

tempfolder = str(Server.objects.filter(host_name=host).values('temp_dir')[0]['temp_dir'])
uploaddir = str(Server.objects.filter(host_name=host).values('upload_dir')[0]['upload_dir'])

def upload_admin_log(request, uploadimage):
    """Log changes to Admin log."""
    change_message = "Uploaded image %s with orientation %s using %s" % (uploadimage.name, uploadimage.orig_orientation, uploadimage.settings)
    action_flag = ADDITION
    try:
      LogEntry.objects.log_action(
        user_id = request.user.id,
        content_type_id = ContentType.objects.get_for_model(Alignment).pk,
        object_id = uploadimage.id,
        object_repr = unicode(uploadimage.name),
        change_message = unicode(change_message),
        action_flag = action_flag,
        )
    except:
        print "Failed to log action."
        print uploadimage

def index(request):
    if not request.user == '':
      cu = int(User.objects.filter(username=request.user).values('id')[0]['id'])
      if cu == 1:
        align_list = Alignment.objects.order_by('alignment_stage', 'name')
        context = {'align_list': align_list}
      else:
        if Alignment.objects.filter(Q(user=cu) | Q(user=0)).count() > 0:
          align_list = Alignment.objects.filter(Q(user=cu) | Q(user=0)).order_by('alignment_stage', 'name')
          context = {'align_list': align_list}
        else:
          context = {}
      return render(request, 'index.html', context)
    else:
      return HttpResponseRedirect('/admin')

def detail(request, image_id):
    if not request.user == '':
      align_list = Alignment.objects.get(id=image_id)
      context = {'record': align_list}
      return render(request, 'details.html', context)
    else:
      return HttpResponseRedirect('/admin')

def handle_uploaded_file(ufile, dest):
    from django.core.files.storage import default_storage
    from django.core.files.base import ContentFile
    path = default_storage.save(dest, ContentFile(ufile.read()))
    return path
    #
    # dest = open(dest, 'wb+')
    # dest.write(ufile)
    # dest.close()

def upload(request):
    from django.contrib import messages
    from django.conf import settings as st
    import os, stat, sys
    # Handle file upload
    if request.method == 'POST':
        form = UploadForm(request.POST, request.FILES)
        if form.is_valid():
            file = str(request.user) + '-' + str(request.FILES['file'])
            setting = Setting.objects.get(id=int(request.POST['settings']))
            if '.tif' in file or '.lsm' in file:
              # file = str(st.MEDIA_URL) + file
              file = handle_uploaded_file(request.FILES['file'], dest=file)
              name = str(os.path.splitext(os.path.basename(file))[0])
              ext = str(os.path.splitext(os.path.basename(file))[1])
              folder = str(st.MEDIA_ROOT)
              ori = str(request.POST['orientation'])
              cu = User.objects.get(username=request.user)
              newimage = Alignment(name=name, orig_orientation=ori, settings=setting, original_path=folder, original_ext=ext, alignment_stage=1, last_host=host, loading_host=host, user=cu)
              newimage.save()
              try:
                os.chmod(folder + os.path.sep + file, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
              except:
                pass
              upload_admin_log(request, newimage)
              return HttpResponseRedirect('/admin/images/alignment/')
            else:
              messages.error(request, 'Not a LSM or tif file')
              return HttpResponseRedirect('/admin/images/alignment/')
        # else:
        # messages.error(request, 'Invalid data')
    else:
        form = UploadForm() # A empty, unbound form

    # Render list page with the documents and the form
    align_list = Alignment.objects.all().order_by('alignment_stage', 'name')
    context = {'align_list': align_list, 'form': form}
    return render_to_response('index.html', context, context_instance=RequestContext(request))

# def showStaticImage(request):
#     """ Simply return a static image as a png """
#     imagePath = "images/default.png"
#     from PIL import Image
#     Image.init()
#     i = Image.open(imagePath)
#     response = HttpResponse(mimetype='image/png')
#     i.save(response,'PNG')
#     return response

def plotResults(request, image_id):
    import os
    import tempfile
    os.environ['MPLCONFIGDIR'] = tempfile.mkdtemp()
    import matplotlib
    from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
    from matplotlib.figure import Figure
    from matplotlib.dates import DateFormatter
    import numpy as np
    fig = Figure()
    ax=fig.add_subplot(3,1,1)
    if Original_nrrd.objects.filter(image=image_id).count() > 0:
      records = Original_nrrd.objects.filter(image=image_id).values()
      chanCol = ['red','green','blue']
      for record in records:
        i = int(record['channel'])
        ax=fig.add_subplot(3,1,i)
        hist = list(record['pre_hist'])
        k = range(0,len(hist))
        v = [long(y) for y in hist]
        m = int(record['new_min'])
        M = int(record['new_max'])
        ax.fill([m,M,M,m], [np.min(v),np.min(v),np.max(v),np.max(v)], 'cyan', fill=True, hatch='/', edgecolor="grey")
        # ax.broken_barh([(m, (M-m))] , (ax.yaxis, (np.max(v)-np.min(v))), facecolors='grey')
        ax.bar(k, v, color=chanCol[i-1])#, log=True

        ax.set_xlim(0,260)
        ax.set_ylim(0,np.max(v))
        ax.set_yscale('symlog', linthreshx=np.average(v))
        ax.grid(True)
        gc.collect()
        ax.set_title('Ch' + str(i) + ' histogram', fontsize=14, color=chanCol[i-1])
    else:
      fig.text(0.3,0.5,'No Data Found!', fontsize=32)
    fig.text(0.5, 0.015, 'Intensity', ha='center', va='center')
    fig.text(0.015, 0.5, 'Count (log)', ha='center', va='center', rotation='vertical')
    fig.tight_layout()
    canvas = FigureCanvas(fig)
    response = HttpResponse(content_type='image/png')
    gc.collect()
    canvas.print_png(response)
    return response

def opositeOr(position):
    Or = {'R':'L','L':'R','P':'A','A':'P','S':'I','I':'S'}
    return Or[position]

def plotNrrd(request, image_id, image_type):
    import os
    import matplotlib
    from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
    from matplotlib.figure import Figure
    from matplotlib.dates import DateFormatter
    import nrrd
    import numpy as np
    import matplotlib.image as mpimg
    import matplotlib.pyplot as plt
    from system.models import checkDir, Server

    labels = False
    Dtemp = False

    file = 'default.png'
    subtext = ''
    orient = 'LPS'
    fsize = 18
    if '_file' in image_type:
      record = checkDir(Alignment.objects.get(id=image_id))
      if Original_nrrd.objects.filter(image=image_id, channel=int(image_type.replace('Ch','').replace('_file',''))).count() > 0:
        temprec = Original_nrrd.objects.get(image=image_id, channel=int(image_type.replace('Ch','').replace('_file','')))
        file = tempfolder + str(temprec.file)
        del temprec
        orient = str(record.settings.template.orientation)
        subtext = 'Orientation: ' + str(comp_orien[orient]) + ' (' + orient + ')'
    elif 'temp_initial_nrrd' in image_type:
      record = checkDir(Alignment.objects.get(id=image_id))
      file = tempfolder + str(record.temp_initial_nrrd)
      orient = str(record.settings.template.orientation)
      subtext = 'Orientation: ' + str(comp_orien[orient]) + ' (' + orient + ')'
    elif 'aligned_bg' in image_type:
      record = checkDir(Alignment.objects.get(id=image_id))
      file = tempfolder + str(record.aligned_bg)
      orient = str(record.settings.template.orientation)
      subtext = 'Orientation: ' + str(comp_orien[orient]) + ' (' + orient + ')'
    elif 'aligned_sg' in image_type:
      record = checkDir(Alignment.objects.get(id=image_id))
      file = tempfolder + str(record.aligned_sg)
      orient = str(record.settings.template.orientation)
      subtext = 'Orientation: ' + str(comp_orien[orient]) + ' (' + orient + ')'
    elif 'aligned_ac1' in image_type:
      record = checkDir(Alignment.objects.get(id=image_id))
      file = tempfolder + str(record.aligned_ac1)
      orient = str(record.settings.template.orientation)
      subtext = 'Orientation: ' + str(comp_orien[orient]) + ' (' + orient + ')'
    elif 'template' in image_type:
      record = Template.objects.get(id=image_id)
      temprec = Server.objects.get(host_name=host)
      file = str(temprec.template_dir) + str(record.file)
      orient = str(record.orientation)
      subtext = 'Orientation: ' + str(comp_orien[orient]) + ' (' + orient + ')'
      del temprec
      fsize = 12
      Dtemp = True
    elif 'mask_original' in image_type:
      record = checkDir(Alignment.objects.get(id=image_id))
      file = tempfolder + str(record.image.file).replace('.nrrd','-objMask.nrrd')
      orient = str(record.image.image.settings.template.orientation)
      subtext = 'Detected objects'
      labels = True
    elif 'mask_aligned_bg' in image_type:
      record = checkDir(Alignment.objects.get(id=image_id))
      # temprec = Original_nrrd.objects.get(id=record.image_id)
      file = tempfolder + str(record.aligned_bg).replace('.nrrd','-objMask.nrrd')
      orient = str(record.settings.template.orientation)
      subtext = 'Detected objects'
      labels = True
    elif 'mask_aligned_sg' in image_type:
      record = checkDir(Alignment.objects.get(id=image_id))
      # temprec = Original_nrrd.objects.get(id=record.image_id)
      file = tempfolder + str(record.aligned_sg).replace('.nrrd','-objMask.nrrd')
      orient = str(record.settings.template.orientation)
      subtext = 'Detected objects'
      labels = True
    elif 'mask_aligned_ac1' in image_type:
      record = checkDir(Alignment.objects.get(id=image_id))
      # temprec = Original_nrrd.objects.get(id=record.image_id)
      file = tempfolder + str(record.aligned_ac1).replace('.nrrd','-objMask.nrrd')
      orient = str(record.settings.template.orientation)
      subtext = 'Detected objects'
      labels = True
    else:
      file = '/static/default.png'
    if os.path.isfile(file):
      ori = list(orient)
      data, header = nrrd.read(file)
      data = data.swapaxes(0,1)
      if labels:
        ulab = np.unique(data)
      zdata = np.max(data, axis=2)
      xdata = np.max(data, axis=1)
      del data
      gc.collect()
      fig = Figure()
      ax=fig.add_subplot(1,2,1)
      imgplot = ax.imshow(xdata)
      imgplot.set_cmap('spectral')
      ax.set_title('Max proj. (X)')
      ax.set_xlabel('Z [' + str(opositeOr(ori[2])) + '->' + str(ori[2]) + '] (Px)', fontsize=10)
      ax.set_ylabel('Y [' + str(ori[1]) + '<-' + str(opositeOr(ori[1])) + '] (Px)')
      ax.yaxis.set_ticks(np.round(np.linspace(ax.get_ylim()[0],ax.get_ylim()[1],3)))
      ax.xaxis.set_ticks(np.round(np.linspace(ax.get_xlim()[0],ax.get_xlim()[1],3)))
      ax=fig.add_subplot(1,2,2)
      imgplot = ax.imshow(zdata)
      imgplot.set_cmap('spectral')

      if labels:
        fig.colorbar(imgplot, ax=ax, aspect=7.5, ticks=ulab)
        fig.suptitle('Detected objects')
      else:
        fig.colorbar(imgplot, ax=ax, aspect=7.5)
        if Dtemp:
          fig.suptitle(str(image_type).replace('temp_initial_nrrd', 'after initial alignment').replace('_',' ').replace('file', 'after preprocessing').title().replace('Template',str(record)).replace('Bg','Background').replace('Sg','Signal').replace('Ac1','Additional Channel 1'), fontsize=fsize)
        else:
          fig.suptitle(str(image_type).replace('temp_initial_nrrd', 'after initial alignment').replace('_',' ').replace('file', 'after preprocessing').title().replace('Template',str(record.settings.template)).replace('Bg','Background').replace('Sg','Signal').replace('Ac1','Additional Channel 1'), fontsize=fsize)
      del xdata, zdata
      gc.collect()
      ax.set_title('Max proj. (Z)')
      ax.set_xlabel('X [' + str(opositeOr(ori[0])) + '->' + str(ori[0]) + '] (Px)')
      ax.set_ylabel('Y [' + str(ori[1]) + '<-' + str(opositeOr(ori[1])) + '] (Px)')
      ax.yaxis.set_ticks(np.round(np.linspace(ax.get_ylim()[0],ax.get_ylim()[1],3)))
      ax.xaxis.set_ticks(np.round(np.linspace(ax.get_xlim()[0],ax.get_xlim()[1],3)))
      fig.text(0.3,0.005,subtext)
      # fig.tight_layout()
      canvas = FigureCanvas(fig)
      response = HttpResponse(content_type='image/png')

      canvas.print_png(response)
      gc.collect()
      return response
    else:
      fig = Figure()
      canvas = FigureCanvas(fig)
      ax=fig.add_subplot(1,1,1)
      ax.set_title('No Image')
      ax.set_xlabel(file, fontsize=8)
      fig.text(0.3,0.5,'No Data Found!', fontsize=32)
      response = HttpResponse(content_type='image/png')
      canvas.print_png(response)
      gc.collect()
      return response
<|endoftext|>


<commit_before>__version__ = '0.6.11'
USER_AGENT = 'log-python-sdk-v-' + __version__
API_VERSION = '0.6.0'

<commit_msg>upgrade to 0.6.12<commit_after>__version__ = '0.6.12'
USER_AGENT = 'log-python-sdk-v-' + __version__
API_VERSION = '0.6.0'

<|endoftext|>


<commit_before>#!/usr/bin/env python
# Copyright (c) 2015 IBM. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
_views_

Utilities for handling design docs and the resulting views they create

"""
import contextlib
import posixpath

from .result import Result, python_to_couch

class Code(str):
    """
    _Code_

    string derived object that allows us to wrap/manipulate javascript blobs

    """
    def __init__(self, s):
        super(Code, self).__init__(s)

def _codify(code_or_str):
    """
    helper to rationalise None, str or Code objects
    """
    if code_or_str is None:
        return None
    if not isinstance(code_or_str, Code):
        return Code(code_or_str)
    return code_or_str

class View(dict):
    """
    Dictionary based object representing a view, exposing the map, reduce
    functions as attributes and supporting query/data access via the view

    Provides a sliceable and iterable default result collection that can
    be used to query the view data via the result attribute.

    Eg:

    Using integers to skip/limit:
    view.result[100:200]
    view.result[:200]
    view.result[100:]

    Using strings or lists as startkey/endkey:

    view.result[ ["2013","10"]:["2013","11"] ]
    view.result[["2013","10"]]
    view.result[["2013","10"]:]

    For large views, iteration is supported via result:

    for doc in view.result:
        print doc

    The default result collection provides basic functionality,
    which can be customised with other arguments to the view URL
    using the custom_result context.

    For example:

    #including documents
    with view.custom_result(include_docs=True) as rslt:
        rslt[100:200] # slice by result
        rslt[["2013","10"]:["2013","11"]] # slice by startkey/endkey

        #iteration
        for doc in rslt:
            print doc

    Iteration over a view within startkey/endkey range:

    with view.custom_result(startkey="2013", endkey="2014") as rslt:
        for doc in rslt:
            print doc

    """
    def __init__(self, ddoc, view_name, map_func=None, reduce_func=None):
        super(View, self).__init__()
        self.design_doc = ddoc
        self._r_session = self.design_doc.r_session
        self.view_name = view_name
        if map_func is not None:
            self['map'] = _codify(map_func)
        if reduce_func is not None:
            self['reduce'] = _codify(reduce_func)
        self.result = Result(self)

    @property
    def map(self):
        """map property getter"""
        return self.get('map')

    @map.setter
    def map(self, js_func):
        """map property setter, accepts str or Code obj"""
        self['map'] = _codify(js_func)

    @property
    def reduce(self):
        """reduce property getter"""
        return self.get('reduce')

    @reduce.setter
    def reduce(self, js_func):
        """reduce property setter, accepts str or Code obj"""
        self['reduce'] = _codify(js_func)

    @property
    def url(self):
        """property that builds the view URL"""
        return posixpath.join(
            self.design_doc.document_url,
            '_view',
            self.view_name
        )

    def __call__(self, **kwargs):
        """
        retrieve data from the view, using the kwargs provided
        as query parameters

        descending bool
        endkey string or array
        endkey_docid  string
        group bool
        group_level ??
        include_docs bool
        inclusive_end  bool
        key string
        limit   int
        reduce  boolean
        skip    int
        stale   enum(ok, update_after)
        startkey  string or array
        startkey_docid  string

        """
        params = python_to_couch(kwargs)
        resp = self._r_session.get(self.url, params=params)
        resp.raise_for_status()
        return resp.json()

    def make_result(self, **options):
        """
        Wrap the call to get result data in a Result object.

        """
        return Result(self, **options)

    @contextlib.contextmanager
    def custom_result(self, **options):
        """
        _custom_result_

        If you want to customise the result behaviour,
        you can build your own with extra options to the result
        call using this context manager.

        Example:

        with view.custom_result(include_docs=True, reduce=False) as rslt:
            data = rslt[100:200]

        """
        rslt = self.make_result(**options)
        yield rslt
        del rslt
<commit_msg>Clean up views module content<commit_after>#!/usr/bin/env python
# Copyright (c) 2015 IBM. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
API module for interacting with a view in a design document.
"""
import contextlib
import posixpath

from .result import Result, python_to_couch

class Code(str):
    """
    Wraps a ``str`` object as a Code object providing the means to handle
    Javascript blob content.  Used internally by the View object when
    codifying map and reduce Javascript content.
    """
    def __init__(self, code):
        super(Code, self).__init__(code)

def _codify(code_or_str):
    """
    Provides a helper to rationalize code content.
    """
    if code_or_str is None:
        return None
    if not isinstance(code_or_str, Code):
        return Code(code_or_str)
    return code_or_str

class View(dict):
    """
    Encapsulates a view as a dictionary based object, exposing the map and
    reduce functions as attributes and supporting query/data access through
    the view.  A View object is instantiated with a reference to a
    DesignDocument and is typically used as part of the
    :class:`~cloudant.design_document.DesignDocument` view management API.

    A View object provides a sliceable and iterable default result collection
    that can be used to query the view data through the ``result`` attribute.

    For example:

    .. code-block:: python

        # Using integers to skip/limit:
        view.result[100:200]
        view.result[:200]
        view.result[100:]

        # Using strings or lists as startkey/endkey:
        view.result[['2013','10']:['2013','11']]
        view.result[['2013','10']]
        view.result[['2013','10']:]

        # Iteration is supported via the result attribute:
        for doc in view.result:
            print doc

    The default ``result`` collection provides basic functionality,
    which can be customized with other arguments using the
    :func:`~cloudant.views.View.custom_result` context.

    For example:

    .. code-block:: python

        # Including documents as part of a custom result
        with view.custom_result(include_docs=True) as rslt:
            rslt[100:200] # slice by result
            rslt[['2013','10']:['2013','11']] # slice by startkey/endkey

            # Iteration
            for doc in rslt:
                print doc

        # Iteration over a view within startkey/endkey range:
        with view.custom_result(startkey='2013', endkey='2014') as rslt:
            for doc in rslt:
                print doc

    Note:  A view must exist as part of a design document remotely in order to
    access result content as depicted in the above examples.

    :param DesignDocument ddoc: DesignDocument instance used in part to
        identify the view.
    :param str view_name: Name used in part to identify the view.
    :param str map_func: Optional Javascript map function.  Can also be a
        :class:`~cloudant.views.Code` object.
    :param str reduce_func: Optional Javascript reduce function.  Can also be a
        :class:`~cloudant.views.Code` object.
    """
    def __init__(self, ddoc, view_name, map_func=None, reduce_func=None):
        super(View, self).__init__()
        self.design_doc = ddoc
        self._r_session = self.design_doc.r_session
        self.view_name = view_name
        if map_func is not None:
            self['map'] = _codify(map_func)
        if reduce_func is not None:
            self['reduce'] = _codify(reduce_func)
        self.result = Result(self)

    @property
    def map(self):
        """
        Provides an map property accessor and setter.  A ``str`` or a ``Code``
        object is acceptable when setting the map property.

        For example:

        .. code-block:: python

            # Set the View map property
            view.map = 'function (doc) {\\n  emit(doc._id, 1);\\n}'
            print view.map

        :param str js_func: Javascript function.  Can also be a
            :class:`~cloudant.views.Code` object.

        :returns: Codified map function
        """
        return self.get('map')

    @map.setter
    def map(self, js_func):
        """
        Provides a map property setter, accepts ``str`` or ``Code`` object.
        """
        self['map'] = _codify(js_func)

    @property
    def reduce(self):
        """
        Provides an reduce property accessor and setter.  A ``str`` or a
        ``Code`` object is acceptable when setting the reduce property.

        For example:

        .. code-block:: python

            # Set the View reduce property
            view.reduce = '_count'
            # Get and print the View reduce property
            print view.reduce

        :param str js_func: Javascript function.  Can also be a
            :class:`~cloudant.views.Code` object.

        :returns: Codified map function
        """
        return self.get('reduce')

    @reduce.setter
    def reduce(self, js_func):
        """
        Provides a reduce property setter, accepts ``str`` or ``Code`` object.
        """
        self['reduce'] = _codify(js_func)

    @property
    def url(self):
        """
        Constructs and returns the View URL.

        :returns: View URL
        """
        return posixpath.join(
            self.design_doc.document_url,
            '_view',
            self.view_name
        )

    def __call__(self, **kwargs):
        """
        Makes the View object callable and retrieves the raw JSON content
        from the remote database based on the View definition on the server,
        using the kwargs provided as query parameters.

        For example:

        .. code-block:: python

            # Construct a View
            view = View(ddoc, 'view001')
            # Assuming that 'view001' exists as part of the
            # design document ddoc in the remote database...
            # Use view as a callable
            for row in view(include_docs=True, limit=100, skip=100)['rows']:
                # Process view data (in JSON format).

        Note:  Rather than using the View callable directly, if you wish to
        retrieve view results in raw JSON format use the provided database API
        of :func:`~cloudant.database.CouchDatabase.get_view_raw_result` instead.

        :param bool descending: Return documents in descending key order.
        :param endkey: Stop returning records at this specified key.  Can be
            either a ``str`` or ``list``.
        :param str endkey_docid: Stop returning records when the specified
            document id is reached.
        :param bool group: Using the reduce function, group the results to a
            group or single row.
        :param group_level: Only applicable if the view uses complex keys: keys
            that are JSON arrays. Groups reduce results for the specified number
            of array fields.
        :param bool include_docs: Include the full content of the documents.
        :param bool inclusive_end: Include rows with the specified endkey.
        :param str key: Return only documents that match the specified key.
        :param list keys: Return only documents that match the specified keys.
        :param int limit: Limit the number of returned documents to the
            specified count.
        :param bool reduce: True to use the reduce function, false otherwise.
        :param int skip: Skip this number of rows from the start.
        :param str stale: Allow the results from a stale view to be used. This
            makes the request return immediately, even if the view has not been
            completely built yet. If this parameter is not given, a response is
            returned only after the view has been built.
        :param startkey: Return records starting with the specified key.  Can be
            either a ``str`` or ``list``
        :param str startkey_docid: Return records starting with the specified
            document ID.

        :returns: View result data in JSON format
        """
        params = python_to_couch(kwargs)
        resp = self._r_session.get(self.url, params=params)
        resp.raise_for_status()
        return resp.json()

    def make_result(self, **options):
        """
        Wraps the raw JSON content of the View object callable in a
        :class:`~cloudant.result.Result` object.  The use of ``skip``
        and ``limit`` as options are not valid when using a Result since the
        ``skip`` and ``limit`` functionality is handled in the Result.

        Note:  Rather than using this method directly, if you wish to
        retrieve view data as a Result object, use the provided database
        API of :func:`~cloudant.database.CouchDatabase.get_view_result` instead.

        :param bool descending: Return documents in descending key order.
        :param endkey: Stop returning records at this specified key.  Can be
            either a ``str`` or ``list``.
        :param str endkey_docid: Stop returning records when the specified
            document id is reached.
        :param bool group: Using the reduce function, group the results to a
            group or single row.
        :param group_level: Only applicable if the view uses complex keys: keys
            that are JSON arrays. Groups reduce results for the specified number
            of array fields.
        :param bool include_docs: Include the full content of the documents.
        :param bool inclusive_end: Include rows with the specified endkey.
        :param str key: Return only documents that match the specified key.
        :param list keys: Return only documents that match the specified keys.
        :param bool reduce: True to use the reduce function, false otherwise.
        :param str stale: Allow the results from a stale view to be used. This
            makes the request return immediately, even if the view has not been
            completely built yet. If this parameter is not given, a response is
            returned only after the view has been built.
        :param startkey: Return records starting with the specified key.  Can be
            either a ``str`` or ``list``
        :param str startkey_docid: Return records starting with the specified
            document ID.

        :returns: View result data wrapped in a Result instance
        """
        return Result(self, **options)

    @contextlib.contextmanager
    def custom_result(self, **options):
        """
        Customizes the :class:`~cloudant.result.Result` behavior and provides
        a convenient context manager for the Result.  Result customizations
        can be made by providing extra options to the result call using this
        context manager.  The use of ``skip`` and ``limit`` as options are not
        valid when using a Result since the ``skip`` and ``limit``
        functionality is handled in the Result.

        For example:

        .. code-block:: python

            with view.custom_result(include_docs=True, reduce=False) as rslt:
                data = rslt[100:200]

        :param bool descending: Return documents in descending key order.
        :param endkey: Stop returning records at this specified key.  Can be
            either a ``str`` or ``list``.
        :param str endkey_docid: Stop returning records when the specified
            document id is reached.
        :param bool group: Using the reduce function, group the results to a
            group or single row.
        :param group_level: Only applicable if the view uses complex keys: keys
            that are JSON arrays. Groups reduce results for the specified number
            of array fields.
        :param bool include_docs: Include the full content of the documents.
        :param bool inclusive_end: Include rows with the specified endkey.
        :param str key: Return only documents that match the specified key.
        :param list keys: Return only documents that match the specified keys.
        :param bool reduce: True to use the reduce function, false otherwise.
        :param str stale: Allow the results from a stale view to be used. This
            makes the request return immediately, even if the view has not been
            completely built yet. If this parameter is not given, a response is
            returned only after the view has been built.
        :param startkey: Return records starting with the specified key.  Can be
            either a ``str`` or ``list``
        :param str startkey_docid: Return records starting with the specified
            document ID.

        :returns: View result data wrapped in a Result instance
        """
        rslt = self.make_result(**options)
        yield rslt
        del rslt
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    Copyright (C) 2013 XCG Consulting (www.xcg-consulting.fr)
#
#    This program 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.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp.osv import fields, osv
from openerp.tools import config
from openerp.tools.translate import _
import re
from lxml import etree
import json

class analytic_structure(osv.Model):

    _name = 'analytic.structure'
    _description = u"Analytic Structure"

    def order_selection(self, cr, uid, context=None):
        order_selection = getattr(self, '_order_selection', None)
        if order_selection is None:
            size = int(config.get_misc('analytic', 'analytic_size', 5))
            order_selection = []
            for n in xrange(1, size + 1):
                order_selection.append((str(n), _(u"Analysis {}".format(n))))
            setattr(self, '_order_selection', order_selection)
        return order_selection

    def _check_unique_ordering_no_company(self, cr, uid, ids, context=None):
        columns = ['company_id', 'model_name', 'ordering']
        structures = self.read(cr, uid, ids, columns, context=context)
        for structure in structures:
            if structure['company_id']:
                continue  # Already checked by the SQL constraint.
            domain = [
                ('model_name', '=', structure['model_name']),
                ('ordering', '=', structure['ordering']),
            ]
            count = self.search(cr, uid, domain, count=True, context=context)
            if count > 1:
                return False
        return True

    _columns = {
        'model_name': fields.char(
            u"Object",
            size=128,
            required=True,
            select='1',
        ),
        'nd_id': fields.many2one(
            'analytic.dimension',
            u"Related Dimension",
            ondelete='restrict',
            required=True,
            select='1',
        ),
        'ordering': fields.selection(
            order_selection,
            u"Analysis slot",
            required=True,
        ),
        'company_id': fields.many2one(
            'res.company',
            u"Company",
        ),
    }

    _defaults = {
        'company_id': lambda *a: False,
    }

    _constraints = [
        (
            _check_unique_ordering_no_company,
            u"One dimension per Analysis slot per object when the structure "
            u"is common to all companies.",
            ['company_id', 'model_name', 'ordering']
        )
    ]

    _sql_constraints = [
        (
            'unique_ordering',
            'unique(company_id,model_name,ordering)',
            u"One dimension per Analysis slot per object per company."
        ),
    ]

    def format_field_name(self, ordering, prefix='a', suffix='id'):
        """Return an analytic field's name from its slot, prefix and suffix.
        """
        return '{pre}{n}_{suf}'.format(pre=prefix, n=ordering, suf=suffix)

    def extract_values(
        self, cr, uid, source, model, prefix='a', suffix='id', dest_model=None,
        dest_prefix=None, dest_suffix=None, context=None
    ):
        """For the given source and destination structures, defined by model,
        prefix and suffix, extract the values of all analytic fields from a
        source. Return the ID of those values, mapped with the field attributed
        to their dimension in the destination structure.

        Use this method to copy analytic data from an object to another.
        The source data can be a browse_record from browse or a dict from read.
        The return value is a dictionary. It can be directly passed as the vals
        or defaults attribute for the ORM methods create, write and copy.

        If not specified, the model, prefix and suffix for the destination
        fields are the same as those for the source fields.
        When a destination model is specified, only the values for dimensions
        present in both models will be returned (at their appropriate slot).
        """

        if dest_prefix is None:
            dest_prefix = prefix
        if dest_suffix is None:
            dest_suffix = suffix

        def add_field():
            src = self.format_field_name(slot, prefix, suffix)
            dest = self.format_field_name(dest_slot, dest_prefix, dest_suffix)
            if src in source:
                try:
                    res[dest] = source[src].id
                except AttributeError:
                    res[dest] = source[src]

        res = {}
        src_dim = self.get_dimensions(cr, uid, model, context=context)

        if dest_model is None or dest_model == model:
            for slot in src_dim.itervalues():
                dest_slot = slot
                add_field()

        else:
            dest_dim = self.get_dimensions(cr, uid, dest_model, context)
            for dimension, slot in src_dim.iteritems():
                if dimension in dest_dim:
                    dest_slot = dest_dim[dimension]
                    add_field()

        return res

    def get_structures(self, cr, uid, model, context=None):
        """Return the browse records of every analytic structure entry
        associated with the given model.
        """
        ans_ids = self.search(
            cr, uid,
            [('model_name', '=', model)],
            context=context
        )
        return self.browse(cr, uid, ans_ids, context=context)

    def get_dimensions(self, cr, uid, model, context=None):
        """Return a dictionary that contains the identifier (keys) and ordering
        number (values) of the analytic dimensions linked to the given model.
        """
        return {
            ans.nd_id.id: ans.ordering
            for ans in self.get_structures(cr, uid, model, context=context)
        }

    def get_dimensions_names(self, cr, uid, model, context=None):
        """Return a dictionary that contains the ordering numbers (keys) and
        names (values) of the analytic dimensions linked to the given model.
        """
        return {
            ans.ordering: ans.nd_id.name
            for ans in self.get_structures(cr, uid, model, context=context)
        }

    def analytic_fields_get(
        self, cr, uid, model, fields, prefix='a', suffix='id', context=None
    ):
        """Set the label values for the analytic fields."""

        ans_dict = self.get_dimensions_names(cr, uid, model, context=context)

        regex = '{pre}(\d+)_{suf}'.format(pre=prefix, suf=suffix)
        match_fct = re.compile(regex).search
        matches = filter(None, map(match_fct, fields.keys()))

        for match in matches:
            field = match.group(0)
            slot = match.group(1)
            fields[field]['string'] = ans_dict.get(
                '{0}'.format(slot),
                '{0}{1}'.format(prefix.upper(), slot)
            )

        return fields

    def analytic_fields_subview_get(
        self, cr, uid, model, field, prefix='a', suffix='id', context=None
    ):
        """Apply analytic_fields_view_get to all subviews defined for a
        given relational field.
        The field argument is a field descriptor found inside the return value
        of fields_view_get. This method both updates and returns it:

        fvg_res = super(model_class, self).fields_view_get(...)
        field = fvg_res['fields'].get(field_name)
        analytic_fields_subview_get(cr, uid, 'analytic_model', field)
        # or...
        if field_name in fvg_res['fields']:
            fvg_res['fields'][field_name] = analytic_fields_subview_get(...)

        Avoid using subviews with analytic fields. It is better to define a new
        ir.ui.view record and pass it with the context key [type]_view_ref.
        """

        try:
            field_subviews = field['views']
        except:
            return field

        for view_mode, subview in field_subviews.iteritems():
            subview['model'] = field['relation']
            field_subviews[view_mode] = self.analytic_fields_view_get(
                cr, uid, model, subview, context=context
            )
        return field

    def analytic_fields_view_get(
        self, cr, uid, model, view, prefix='a', suffix='id', context=None
    ):
        """Show or hide used/unused analytic fields."""

        ans_dict = self.get_dimensions_names(cr, uid, model, context=context)
        found_fields = {slot: False for slot in ans_dict}

        regex = '{pre}(\d+)_{suf}'.format(pre=prefix, suf=suffix)
        path = "//field[re:match(@name, '{0}')]".format(regex)
        ns = {"re": "http://exslt.org/regular-expressions"}

        doc = etree.XML(view['arch'])
        matches = doc.xpath(path, namespaces=ns)

        for match in matches:
            name = match.get('name')
            slot = re.search(regex, name).group(1)
            if slot in found_fields:
                # The analytic field is used and has been found in the view.
                found_fields[slot] = True
            else:
                # No analytic structure defined for this field, hide it.
                modifiers = json.loads(match.get('modifiers', '{}'))
                modifiers['invisible'] = modifiers['tree_invisible'] = True
                modifiers['required'] = False
                match.set('invisible', 'true')
                match.set('required', 'false')
                match.set('modifiers', json.dumps(modifiers))

        # Look for a div with the 'oe_analytic' class and the right prefix.
        cls_cond = 'contains(@class, "oe_analytic")'
        if prefix == 'a':
            pre_cond = '(@prefix="a" or not(@prefix))'
        else:
            pre_cond = '@prefix="{pre}"'.format(pre=prefix)
        if suffix == 'id':
            suf_cond = '(@suffix="id" or not(@suffix))'
        else:
            suf_cond = '@suffix="{suf}"'.format(suf=suffix)
        condition = '{0} and {1} and {2}'.format(cls_cond, pre_cond, suf_cond)
        parent_matches = doc.xpath('//div[{cond}]/..'.format(cond=condition))

        if parent_matches:

            parent = parent_matches[0]
            div = parent.xpath("//div[{cond}]".format(cond=condition))[0]
            for index, child in enumerate(parent):
                if child == div:
                    break
            next_children = parent[index + 1:]
            del parent[index:]

            # Get all fields that are in the structure but not in the view.
            sorted_fields = found_fields.items()
            sorted_fields.sort(key=lambda i: int(i[0]))
            div_fields = [
                self.format_field_name(ordering, prefix, suffix)
                for ordering, found in sorted_fields if not found
            ]

            # First, we have to load the definitions for those fields.
            if div_fields:
                div_fields_def = self.pool.get(view['model']).fields_get(
                    cr, uid, div_fields, context=context
                )
                view['fields'].update(div_fields_def)

                # Now we can insert the fields in the view's architecture.
                for field in div_fields:
                    attrs = {'name': field}
                    for attr, value in div.attrib.iteritems():
                        if attr in ['class', 'prefix']:
                            continue
                        attrs[attr] = value
                    parent.append(etree.Element('field', attrs))

                parent.extend(next_children)

        view['arch'] = etree.tostring(doc)

        return view
<commit_msg>analytic_fields_view_get: fixed an issue when using the oe_analytic div for tree views. Fields are now generated with an empty JSON dict as their default 'modifiers' attribute.<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    Copyright (C) 2013 XCG Consulting (www.xcg-consulting.fr)
#
#    This program 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.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp.osv import fields, osv
from openerp.tools import config
from openerp.tools.translate import _
import re
from lxml import etree
import json

class analytic_structure(osv.Model):

    _name = 'analytic.structure'
    _description = u"Analytic Structure"

    def order_selection(self, cr, uid, context=None):
        order_selection = getattr(self, '_order_selection', None)
        if order_selection is None:
            size = int(config.get_misc('analytic', 'analytic_size', 5))
            order_selection = []
            for n in xrange(1, size + 1):
                order_selection.append((str(n), _(u"Analysis {}".format(n))))
            setattr(self, '_order_selection', order_selection)
        return order_selection

    def _check_unique_ordering_no_company(self, cr, uid, ids, context=None):
        columns = ['company_id', 'model_name', 'ordering']
        structures = self.read(cr, uid, ids, columns, context=context)
        for structure in structures:
            if structure['company_id']:
                continue  # Already checked by the SQL constraint.
            domain = [
                ('model_name', '=', structure['model_name']),
                ('ordering', '=', structure['ordering']),
            ]
            count = self.search(cr, uid, domain, count=True, context=context)
            if count > 1:
                return False
        return True

    _columns = {
        'model_name': fields.char(
            u"Object",
            size=128,
            required=True,
            select='1',
        ),
        'nd_id': fields.many2one(
            'analytic.dimension',
            u"Related Dimension",
            ondelete='restrict',
            required=True,
            select='1',
        ),
        'ordering': fields.selection(
            order_selection,
            u"Analysis slot",
            required=True,
        ),
        'company_id': fields.many2one(
            'res.company',
            u"Company",
        ),
    }

    _defaults = {
        'company_id': lambda *a: False,
    }

    _constraints = [
        (
            _check_unique_ordering_no_company,
            u"One dimension per Analysis slot per object when the structure "
            u"is common to all companies.",
            ['company_id', 'model_name', 'ordering']
        )
    ]

    _sql_constraints = [
        (
            'unique_ordering',
            'unique(company_id,model_name,ordering)',
            u"One dimension per Analysis slot per object per company."
        ),
    ]

    def format_field_name(self, ordering, prefix='a', suffix='id'):
        """Return an analytic field's name from its slot, prefix and suffix.
        """
        return '{pre}{n}_{suf}'.format(pre=prefix, n=ordering, suf=suffix)

    def extract_values(
        self, cr, uid, source, model, prefix='a', suffix='id', dest_model=None,
        dest_prefix=None, dest_suffix=None, context=None
    ):
        """For the given source and destination structures, defined by model,
        prefix and suffix, extract the values of all analytic fields from a
        source. Return the ID of those values, mapped with the field attributed
        to their dimension in the destination structure.

        Use this method to copy analytic data from an object to another.
        The source data can be a browse_record from browse or a dict from read.
        The return value is a dictionary. It can be directly passed as the vals
        or defaults attribute for the ORM methods create, write and copy.

        If not specified, the model, prefix and suffix for the destination
        fields are the same as those for the source fields.
        When a destination model is specified, only the values for dimensions
        present in both models will be returned (at their appropriate slot).
        """

        if dest_prefix is None:
            dest_prefix = prefix
        if dest_suffix is None:
            dest_suffix = suffix

        def add_field():
            src = self.format_field_name(slot, prefix, suffix)
            dest = self.format_field_name(dest_slot, dest_prefix, dest_suffix)
            if src in source:
                try:
                    res[dest] = source[src].id
                except AttributeError:
                    res[dest] = source[src]

        res = {}
        src_dim = self.get_dimensions(cr, uid, model, context=context)

        if dest_model is None or dest_model == model:
            for slot in src_dim.itervalues():
                dest_slot = slot
                add_field()

        else:
            dest_dim = self.get_dimensions(cr, uid, dest_model, context)
            for dimension, slot in src_dim.iteritems():
                if dimension in dest_dim:
                    dest_slot = dest_dim[dimension]
                    add_field()

        return res

    def get_structures(self, cr, uid, model, context=None):
        """Return the browse records of every analytic structure entry
        associated with the given model.
        """
        ans_ids = self.search(
            cr, uid,
            [('model_name', '=', model)],
            context=context
        )
        return self.browse(cr, uid, ans_ids, context=context)

    def get_dimensions(self, cr, uid, model, context=None):
        """Return a dictionary that contains the identifier (keys) and ordering
        number (values) of the analytic dimensions linked to the given model.
        """
        return {
            ans.nd_id.id: ans.ordering
            for ans in self.get_structures(cr, uid, model, context=context)
        }

    def get_dimensions_names(self, cr, uid, model, context=None):
        """Return a dictionary that contains the ordering numbers (keys) and
        names (values) of the analytic dimensions linked to the given model.
        """
        return {
            ans.ordering: ans.nd_id.name
            for ans in self.get_structures(cr, uid, model, context=context)
        }

    def analytic_fields_get(
        self, cr, uid, model, fields, prefix='a', suffix='id', context=None
    ):
        """Set the label values for the analytic fields."""

        ans_dict = self.get_dimensions_names(cr, uid, model, context=context)

        regex = '{pre}(\d+)_{suf}'.format(pre=prefix, suf=suffix)
        match_fct = re.compile(regex).search
        matches = filter(None, map(match_fct, fields.keys()))

        for match in matches:
            field = match.group(0)
            slot = match.group(1)
            fields[field]['string'] = ans_dict.get(
                '{0}'.format(slot),
                '{0}{1}'.format(prefix.upper(), slot)
            )

        return fields

    def analytic_fields_subview_get(
        self, cr, uid, model, field, prefix='a', suffix='id', context=None
    ):
        """Apply analytic_fields_view_get to all subviews defined for a
        given relational field.
        The field argument is a field descriptor found inside the return value
        of fields_view_get. This method both updates and returns it:

        fvg_res = super(model_class, self).fields_view_get(...)
        field = fvg_res['fields'].get(field_name)
        analytic_fields_subview_get(cr, uid, 'analytic_model', field)
        # or...
        if field_name in fvg_res['fields']:
            fvg_res['fields'][field_name] = analytic_fields_subview_get(...)

        Avoid using subviews with analytic fields. It is better to define a new
        ir.ui.view record and pass it with the context key [type]_view_ref.
        """

        try:
            field_subviews = field['views']
        except:
            return field

        for view_mode, subview in field_subviews.iteritems():
            subview['model'] = field['relation']
            field_subviews[view_mode] = self.analytic_fields_view_get(
                cr, uid, model, subview, context=context
            )
        return field

    def analytic_fields_view_get(
        self, cr, uid, model, view, prefix='a', suffix='id', context=None
    ):
        """Show or hide used/unused analytic fields."""

        ans_dict = self.get_dimensions_names(cr, uid, model, context=context)
        found_fields = {slot: False for slot in ans_dict}

        regex = '{pre}(\d+)_{suf}'.format(pre=prefix, suf=suffix)
        path = "//field[re:match(@name, '{0}')]".format(regex)
        ns = {"re": "http://exslt.org/regular-expressions"}

        doc = etree.XML(view['arch'])
        matches = doc.xpath(path, namespaces=ns)

        for match in matches:
            name = match.get('name')
            slot = re.search(regex, name).group(1)
            if slot in found_fields:
                # The analytic field is used and has been found in the view.
                found_fields[slot] = True
            else:
                # No analytic structure defined for this field, hide it.
                modifiers = json.loads(match.get('modifiers', '{}'))
                modifiers['invisible'] = modifiers['tree_invisible'] = True
                modifiers['required'] = False
                match.set('invisible', 'true')
                match.set('required', 'false')
                match.set('modifiers', json.dumps(modifiers))

        # Look for a div with the 'oe_analytic' class and the right prefix.
        cls_cond = 'contains(@class, "oe_analytic")'
        if prefix == 'a':
            pre_cond = '(@prefix="a" or not(@prefix))'
        else:
            pre_cond = '@prefix="{pre}"'.format(pre=prefix)
        if suffix == 'id':
            suf_cond = '(@suffix="id" or not(@suffix))'
        else:
            suf_cond = '@suffix="{suf}"'.format(suf=suffix)
        condition = '{0} and {1} and {2}'.format(cls_cond, pre_cond, suf_cond)
        parent_matches = doc.xpath('//div[{cond}]/..'.format(cond=condition))

        if parent_matches:

            parent = parent_matches[0]
            div = parent.xpath("//div[{cond}]".format(cond=condition))[0]
            for index, child in enumerate(parent):
                if child == div:
                    break
            next_children = parent[index + 1:]
            del parent[index:]

            # Get all fields that are in the structure but not in the view.
            sorted_fields = found_fields.items()
            sorted_fields.sort(key=lambda i: int(i[0]))
            div_fields = [
                self.format_field_name(ordering, prefix, suffix)
                for ordering, found in sorted_fields if not found
            ]

            # First, we have to load the definitions for those fields.
            if div_fields:
                div_fields_def = self.pool.get(view['model']).fields_get(
                    cr, uid, div_fields, context=context
                )
                view['fields'].update(div_fields_def)

                # Now we can insert the fields in the view's architecture.
                for field in div_fields:
                    attrs = {'name': field, 'modifiers': '{}'}
                    for attr, value in div.attrib.iteritems():
                        if attr in ['class', 'prefix']:
                            continue
                        attrs[attr] = value
                    parent.append(etree.Element('field', attrs))

                parent.extend(next_children)

        view['arch'] = etree.tostring(doc)

        return view
<|endoftext|>


<commit_before>import json

from django.shortcuts import render_to_response
from django.template import RequestContext
from django.db import transaction
from django.core.urlresolvers import resolve
from django.views.decorators.cache import cache_page

from angkot.decorators import api, OK, Fail, post_only
from .models import Transportation, Submission, PROVINCES
from .submission.data import process as processSubmission
from .forms import NewTransportationForm
from . import utils

def _format_date(d):
    return d.strftime('%s')

@api
def _new_transportation(request):
    f = NewTransportationForm(request.POST)
    if not f.is_valid():
        return Fail(http_code=400, error_code=400,
                    error_msg='Request requires province, city, and number; ' \
                              'and accept the contributor terms')

    province = f.cleaned_data['province']
    city = f.cleaned_data['city']
    number = f.cleaned_data['number']
    company = f.cleaned_data['company']

    code = 200
    submission_id = None
    with transaction.commit_on_success():
        s = Submission()
        s.ip_address = request.META['REMOTE_ADDR']
        s.user_agent = request.META['HTTP_USER_AGENT']
        s.user = request.user
        s.raw_geojson = json.dumps(utils.create_geojson_feature(
            province=province,
            city=city,
            number=number,
            company=company,
            agreeToContributorTerms=True))
        s.source = 'web'
        s.save()

        items = Transportation.objects.filter(active=True, province=province,
                                              city=city, number=number)

        assert len(items) in [0, 1]
        if len(items) > 0:
            t = items[0]
        else:
            t = Transportation(active=True, province=province,
                               city=city, number=number, company=company)
            t.save()

            s.transportation = t
            s.save()

            code = 201

    data = dict(id=t.id,
                province=t.province,
                city=t.city,
                number=t.number,
                company=t.company,
                submission_id=s.submission_id)

    return OK(data, code)

def index(request):
    if request.method == 'POST':
        return _new_transportation(request)
    return render_to_response('route/index.html',
                              context_instance=RequestContext(request))

@api
def submission_list(request):
    batch = 25
    start = int(request.GET.get('start', 0))

    items = Submission.objects.filter(active=True)
    items = items[start:start+batch]

    def format_item(item):
        return dict(created=int(item.created.strftime("%s")),
                    geojson=item.to_geojson())

    submissions = [format_item(item) for item in items]

    data = dict(submissions=submissions)
    return OK(data)

@api
def province_list(request):
    return dict(provinces=PROVINCES)

@cache_page(24 * 60 * 60)
def province_list_js(request):
    data = dict(provinces=json.dumps(PROVINCES))
    return render_to_response('route/province-list.js', data,
                              content_type='text/javascript',
                              context_instance=RequestContext(request))

@api
def transportation_list(request):
    # TODO cache this
    def format_transportation(t):
        return dict(id=t.id,
                    province=t.province,
                    city=t.city,
                    company=t.company,
                    number=t.number,
                    origin=t.origin,
                    destination=t.destination,
                    created=_format_date(t.created),
                    updated=_format_date(t.updated),
                    hasRoute=t.route is not None)

    items = Transportation.objects.filter(active=True)
    transportations = map(format_transportation, items)

    return dict(provinces=PROVINCES,
                transportations=transportations)

@api
def transportation_data(request, tid):
    tid = int(tid)
    t = Transportation.objects.get(pk=tid)

    return dict(id=t.id,
                geojson=t.to_geojson(),
                created=_format_date(t.created),
                updated=_format_date(t.updated))

@api
@post_only
def transportation_data_save(request, tid):
    import geojson
    from shapely.geometry import asShape

    tid = int(tid)
    t = Transportation.objects.get(pk=tid)

    raw = request.POST['geojson']
    print raw
    parent_id = request.POST.get('parent_id', None)
    try:
        parent = Submission.objects.get(submission_id=parent_id)
    except Submission.DoesNotExist:
        parent = None

    s = Submission()
    s.parent = parent
    s.ip_address = request.META['REMOTE_ADDR']
    s.user_agent = request.META['HTTP_USER_AGENT']
    s.user = request.user
    s.raw_geojson = raw
    s.source = 'web'
    s.save()

    processSubmission(s)
    if s.parsed_ok:
        s.transportation = t
    s.save()

    if s.parsed_ok:
        # Update transportation
        # province, city, and number are not updated from here
        t.company = s.company
        t.origin = s.origin
        t.destination = s.destination
        t.route = s.route
        t.submission = s
        t.save()

    data = dict(submission_id=s.submission_id)
    if s.parsed_ok:
        res = OK(data, http_code=201)
    else:
        res = Fail(data, http_code=400,
                   error_code=400, error_msg='Invalid data')
    return res

<commit_msg>Associate submission to a transportation<commit_after>import json

from django.shortcuts import render_to_response
from django.template import RequestContext
from django.db import transaction
from django.core.urlresolvers import resolve
from django.views.decorators.cache import cache_page

from angkot.decorators import api, OK, Fail, post_only
from .models import Transportation, Submission, PROVINCES
from .submission.data import process as processSubmission
from .forms import NewTransportationForm
from . import utils

def _format_date(d):
    return d.strftime('%s')

@api
def _new_transportation(request):
    f = NewTransportationForm(request.POST)
    if not f.is_valid():
        return Fail(http_code=400, error_code=400,
                    error_msg='Request requires province, city, and number; ' \
                              'and accept the contributor terms')

    province = f.cleaned_data['province']
    city = f.cleaned_data['city']
    number = f.cleaned_data['number']
    company = f.cleaned_data['company']

    code = 200
    submission_id = None
    with transaction.commit_on_success():
        s = Submission()
        s.ip_address = request.META['REMOTE_ADDR']
        s.user_agent = request.META['HTTP_USER_AGENT']
        s.user = request.user
        s.raw_geojson = json.dumps(utils.create_geojson_feature(
            province=province,
            city=city,
            number=number,
            company=company,
            agreeToContributorTerms=True))
        s.source = 'web'
        s.save()

        items = Transportation.objects.filter(active=True, province=province,
                                              city=city, number=number)

        assert len(items) in [0, 1]
        if len(items) > 0:
            t = items[0]
        else:
            t = Transportation(active=True, province=province,
                               city=city, number=number, company=company)
            t.save()

            s.transportation = t
            s.save()

            code = 201

        s.transportation = t
        s.save()

    data = dict(id=t.id,
                province=t.province,
                city=t.city,
                number=t.number,
                company=t.company,
                submission_id=s.submission_id)

    return OK(data, code)

def index(request):
    if request.method == 'POST':
        return _new_transportation(request)
    return render_to_response('route/index.html',
                              context_instance=RequestContext(request))

@api
def submission_list(request):
    batch = 25
    start = int(request.GET.get('start', 0))

    items = Submission.objects.filter(active=True)
    items = items[start:start+batch]

    def format_item(item):
        return dict(created=int(item.created.strftime("%s")),
                    geojson=item.to_geojson())

    submissions = [format_item(item) for item in items]

    data = dict(submissions=submissions)
    return OK(data)

@api
def province_list(request):
    return dict(provinces=PROVINCES)

@cache_page(24 * 60 * 60)
def province_list_js(request):
    data = dict(provinces=json.dumps(PROVINCES))
    return render_to_response('route/province-list.js', data,
                              content_type='text/javascript',
                              context_instance=RequestContext(request))

@api
def transportation_list(request):
    # TODO cache this
    def format_transportation(t):
        return dict(id=t.id,
                    province=t.province,
                    city=t.city,
                    company=t.company,
                    number=t.number,
                    origin=t.origin,
                    destination=t.destination,
                    created=_format_date(t.created),
                    updated=_format_date(t.updated),
                    hasRoute=t.route is not None)

    items = Transportation.objects.filter(active=True)
    transportations = map(format_transportation, items)

    return dict(provinces=PROVINCES,
                transportations=transportations)

@api
def transportation_data(request, tid):
    tid = int(tid)
    t = Transportation.objects.get(pk=tid)

    return dict(id=t.id,
                geojson=t.to_geojson(),
                created=_format_date(t.created),
                updated=_format_date(t.updated))

@api
@post_only
def transportation_data_save(request, tid):
    import geojson
    from shapely.geometry import asShape

    tid = int(tid)
    t = Transportation.objects.get(pk=tid)

    raw = request.POST['geojson']
    print raw
    parent_id = request.POST.get('parent_id', None)
    try:
        parent = Submission.objects.get(submission_id=parent_id)
    except Submission.DoesNotExist:
        parent = None

    s = Submission()
    s.parent = parent
    s.ip_address = request.META['REMOTE_ADDR']
    s.user_agent = request.META['HTTP_USER_AGENT']
    s.user = request.user
    s.raw_geojson = raw
    s.source = 'web'
    s.save()

    processSubmission(s)
    if s.parsed_ok:
        s.transportation = t
    s.save()

    if s.parsed_ok:
        # Update transportation
        # province, city, and number are not updated from here
        t.company = s.company
        t.origin = s.origin
        t.destination = s.destination
        t.route = s.route
        t.submission = s
        t.save()

    data = dict(submission_id=s.submission_id)
    if s.parsed_ok:
        res = OK(data, http_code=201)
    else:
        res = Fail(data, http_code=400,
                   error_code=400, error_msg='Invalid data')
    return res

<|endoftext|>


<commit_before>import json
import logging

from django.shortcuts import render_to_response
from django.template import RequestContext
from django.db import transaction
from django.core.urlresolvers import resolve
from django.views.decorators.cache import cache_page

from angkot.decorators import api, OK, Fail, api_post_only, api_login_required
from angkot.utils import log_extra
from .models import Transportation, Submission, PROVINCES
from .submission.data import process as processSubmission
from .forms import NewTransportationForm
from . import utils

log = logging.getLogger(__name__)

def _format_date(d):
    return d.strftime('%s')

@api
@api_login_required
def _new_transportation(request):
    _e = log_extra(request)

    f = NewTransportationForm(request.POST)
    if not f.is_valid():
        log.error('new transportation: incomplete data', extra=_e)
        return Fail(http_code=400, error_code=400,
                    error_msg='Request requires province, city, and number; ' \
                              'and accept the contributor terms')

    province = f.cleaned_data['province']
    city = f.cleaned_data['city']
    number = f.cleaned_data['number']
    company = f.cleaned_data['company']

    city = utils.capwords(city)
    if company is not None:
        company = utils.capwords(company)

    code = 200
    submission_id = None
    with transaction.commit_on_success():
        s = Submission()
        s.ip_address = request.META['REMOTE_ADDR']
        s.user_agent = request.META['HTTP_USER_AGENT']
        s.user = request.user
        s.raw_geojson = json.dumps(utils.create_geojson_feature(
            province=province,
            city=city,
            number=number,
            company=company,
            agreeToContributorTerms=True))
        s.source = 'web'
        processSubmission(s)
        s.save()

        items = Transportation.objects.filter(active=True, province=province,
                                              city=city, number=number)

        assert len(items) in [0, 1]
        if len(items) > 0:
            t = items[0]
        else:
            t = Transportation(active=True, province=province,
                               city=city, number=number, company=company)
            t.save()

            s.transportation = t
            s.save()

            code = 201

        s.transportation = t
        s.save()

        log.info('new transportation: added: sid=%d tid=%d', s.id, t.id, extra=_e)

    data = dict(id=t.id,
                province=t.province,
                city=t.city,
                number=t.number,
                company=t.company,
                submission_id=s.submission_id)

    return OK(data, code)

def index(request):
    if request.method == 'POST':
        return _new_transportation(request)
    return render_to_response('route/index.html',
                              context_instance=RequestContext(request))

@api
def submission_list(request):
    batch = 25
    start = int(request.GET.get('start', 0))

    items = Submission.objects.filter(active=True)
    items = items[start:start+batch]

    def format_item(item):
        return dict(created=int(item.created.strftime("%s")),
                    geojson=item.to_geojson())

    submissions = [format_item(item) for item in items]

    data = dict(submissions=submissions)
    return OK(data)

@api
def province_list(request):
    return dict(provinces=PROVINCES)

@cache_page(24 * 60 * 60)
def province_list_js(request):
    data = dict(provinces=json.dumps(PROVINCES))
    return render_to_response('route/province-list.js', data,
                              content_type='text/javascript',
                              context_instance=RequestContext(request))

@api
def transportation_list(request):
    # TODO cache this
    def format_transportation(t):
        return dict(id=t.id,
                    province=t.province,
                    city=t.city,
                    company=t.company,
                    number=t.number,
                    origin=t.origin,
                    destination=t.destination,
                    created=_format_date(t.created),
                    updated=_format_date(t.updated),
                    hasRoute=t.route is not None)

    items = Transportation.objects.filter(active=True)
    transportations = map(format_transportation, items)

    return dict(provinces=PROVINCES,
                transportations=transportations)

@api
def transportation_data(request, tid):
    tid = int(tid)
    t = Transportation.objects.get(pk=tid)

    sid = None
    if t.submission is not None:
        sid = t.submission.submission_id

    return dict(id=t.id,
                submission_id=sid,
                geojson=t.to_geojson(),
                created=_format_date(t.created),
                updated=_format_date(t.updated))

@api
@api_post_only
@api_login_required
def transportation_data_save(request, tid):
    _e = log_extra(request)

    import geojson
    from shapely.geometry import asShape

    tid = int(tid)
    try:
        t = Transportation.objects.get(pk=tid)
    except Transportation.DoesNotExist:
        log.error('save transportation: invalid id: tid=%s', tid, extra=_e)
        return Fail(http_code=404, error_code=404,
                    error_msg='Unknown transportation id: {}'.format(tid))

    raw = request.POST['geojson']
    parent_id = request.POST.get('parent_id', None)

    log.info('save transportation: received data: parent=%s geojson=%s',
             parent_id, raw, extra=_e)

    try:
        parent = Submission.objects.get(submission_id=parent_id)
    except Submission.DoesNotExist:
        parent = None

    s = Submission()
    s.parent = parent
    s.ip_address = request.META['REMOTE_ADDR']
    s.user_agent = request.META['HTTP_USER_AGENT']
    s.user = request.user
    s.raw_geojson = raw
    s.source = 'web'
    s.save()

    processSubmission(s)
    if s.parsed_ok:
        s.transportation = t
        s.city = utils.capwords(s.city)
        if s.company is not None:
            s.company = utils.capwords(s.company)
    s.save()

    if s.parsed_ok:
        # Update transportation
        t.province = s.province
        t.city = s.city
        t.company = s.company
        t.number = s.number
        t.origin = s.origin
        t.destination = s.destination
        t.route = s.route
        t.submission = s
        t.save()
        log.info('save transportation: saved: sid=%d tid=%d', s.id, t.id, extra=_e)

    else:
        log.info('save transportation: invalid data: sid=%d', s.id, extra=_e)

    data = dict(submission_id=s.submission_id)
    if s.parsed_ok:
        res = OK(data, http_code=201)
    else:
        res = Fail(data, http_code=400,
                   error_code=400, error_msg='Invalid data')
    return res

<commit_msg>Return 404 if the requested data is not available<commit_after>import json
import logging

from django.shortcuts import render_to_response
from django.template import RequestContext
from django.db import transaction
from django.core.urlresolvers import resolve
from django.views.decorators.cache import cache_page

from angkot.decorators import api, OK, Fail, api_post_only, api_login_required
from angkot.utils import log_extra
from .models import Transportation, Submission, PROVINCES
from .submission.data import process as processSubmission
from .forms import NewTransportationForm
from . import utils

log = logging.getLogger(__name__)

def _format_date(d):
    return d.strftime('%s')

@api
@api_login_required
def _new_transportation(request):
    _e = log_extra(request)

    f = NewTransportationForm(request.POST)
    if not f.is_valid():
        log.error('new transportation: incomplete data', extra=_e)
        return Fail(http_code=400, error_code=400,
                    error_msg='Request requires province, city, and number; ' \
                              'and accept the contributor terms')

    province = f.cleaned_data['province']
    city = f.cleaned_data['city']
    number = f.cleaned_data['number']
    company = f.cleaned_data['company']

    city = utils.capwords(city)
    if company is not None:
        company = utils.capwords(company)

    code = 200
    submission_id = None
    with transaction.commit_on_success():
        s = Submission()
        s.ip_address = request.META['REMOTE_ADDR']
        s.user_agent = request.META['HTTP_USER_AGENT']
        s.user = request.user
        s.raw_geojson = json.dumps(utils.create_geojson_feature(
            province=province,
            city=city,
            number=number,
            company=company,
            agreeToContributorTerms=True))
        s.source = 'web'
        processSubmission(s)
        s.save()

        items = Transportation.objects.filter(active=True, province=province,
                                              city=city, number=number)

        assert len(items) in [0, 1]
        if len(items) > 0:
            t = items[0]
        else:
            t = Transportation(active=True, province=province,
                               city=city, number=number, company=company)
            t.save()

            s.transportation = t
            s.save()

            code = 201

        s.transportation = t
        s.save()

        log.info('new transportation: added: sid=%d tid=%d', s.id, t.id, extra=_e)

    data = dict(id=t.id,
                province=t.province,
                city=t.city,
                number=t.number,
                company=t.company,
                submission_id=s.submission_id)

    return OK(data, code)

def index(request):
    if request.method == 'POST':
        return _new_transportation(request)
    return render_to_response('route/index.html',
                              context_instance=RequestContext(request))

@api
def submission_list(request):
    batch = 25
    start = int(request.GET.get('start', 0))

    items = Submission.objects.filter(active=True)
    items = items[start:start+batch]

    def format_item(item):
        return dict(created=int(item.created.strftime("%s")),
                    geojson=item.to_geojson())

    submissions = [format_item(item) for item in items]

    data = dict(submissions=submissions)
    return OK(data)

@api
def province_list(request):
    return dict(provinces=PROVINCES)

@cache_page(24 * 60 * 60)
def province_list_js(request):
    data = dict(provinces=json.dumps(PROVINCES))
    return render_to_response('route/province-list.js', data,
                              content_type='text/javascript',
                              context_instance=RequestContext(request))

@api
def transportation_list(request):
    # TODO cache this
    def format_transportation(t):
        return dict(id=t.id,
                    province=t.province,
                    city=t.city,
                    company=t.company,
                    number=t.number,
                    origin=t.origin,
                    destination=t.destination,
                    created=_format_date(t.created),
                    updated=_format_date(t.updated),
                    hasRoute=t.route is not None)

    items = Transportation.objects.filter(active=True)
    transportations = map(format_transportation, items)

    return dict(provinces=PROVINCES,
                transportations=transportations)

@api
def transportation_data(request, tid):
    tid = int(tid)
    try:
        t = Transportation.objects.get(pk=tid, active=True)
    except Transportation.DoesNotExist:
        return Fail(http_code=404, error_code=404,
                    error_msg='Unknown transportation id: {}'.format(tid))

    sid = None
    if t.submission is not None:
        sid = t.submission.submission_id

    return dict(id=t.id,
                submission_id=sid,
                geojson=t.to_geojson(),
                created=_format_date(t.created),
                updated=_format_date(t.updated))

@api
@api_post_only
@api_login_required
def transportation_data_save(request, tid):
    _e = log_extra(request)

    import geojson
    from shapely.geometry import asShape

    tid = int(tid)
    try:
        t = Transportation.objects.get(pk=tid)
    except Transportation.DoesNotExist:
        log.error('save transportation: invalid id: tid=%s', tid, extra=_e)
        return Fail(http_code=404, error_code=404,
                    error_msg='Unknown transportation id: {}'.format(tid))

    raw = request.POST['geojson']
    parent_id = request.POST.get('parent_id', None)

    log.info('save transportation: received data: parent=%s geojson=%s',
             parent_id, raw, extra=_e)

    try:
        parent = Submission.objects.get(submission_id=parent_id)
    except Submission.DoesNotExist:
        parent = None

    s = Submission()
    s.parent = parent
    s.ip_address = request.META['REMOTE_ADDR']
    s.user_agent = request.META['HTTP_USER_AGENT']
    s.user = request.user
    s.raw_geojson = raw
    s.source = 'web'
    s.save()

    processSubmission(s)
    if s.parsed_ok:
        s.transportation = t
        s.city = utils.capwords(s.city)
        if s.company is not None:
            s.company = utils.capwords(s.company)
    s.save()

    if s.parsed_ok:
        # Update transportation
        t.province = s.province
        t.city = s.city
        t.company = s.company
        t.number = s.number
        t.origin = s.origin
        t.destination = s.destination
        t.route = s.route
        t.submission = s
        t.save()
        log.info('save transportation: saved: sid=%d tid=%d', s.id, t.id, extra=_e)

    else:
        log.info('save transportation: invalid data: sid=%d', s.id, extra=_e)

    data = dict(submission_id=s.submission_id)
    if s.parsed_ok:
        res = OK(data, http_code=201)
    else:
        res = Fail(data, http_code=400,
                   error_code=400, error_msg='Invalid data')
    return res

<|endoftext|>


<commit_before>from django.conf.urls.defaults import *

from announcements.views import detail, dismiss
from announcements.views import CreateAnnouncementView, UpdateAnnouncementView
from announcements.views import DeleteAnnouncementView, AnnouncementListView

urlpatterns = patterns("",
    url(r"^$", AnnouncementListView.as_view(), name="announcements_list"),
    url(r"^announcement/create/$", CreateAnnouncementView.as_view(), name="announcements_create"),
    url(r"^announcement/(?P<pk>\d+)/$", detail, name="announcements_detail"),
    url(r"^announcement/(?P<pk>\d+)/hide/$", dismiss, name="announcements_dismiss"),
    url(r"^announcement/(?P<pk>\d+)/update/$", UpdateAnnouncementView.as_view(), name="announcements_update"),
    url(r"^announcement/(?P<pk>\d+)/delete/$", DeleteAnnouncementView.as_view(), name="announcements_delete"),
)
<commit_msg>make url compatible with django 1.6<commit_after>try:
    from django.conf.urls import url, patterns
except ImportError:
    from django.conf.urls.defaults import url, patterns

from announcements.views import detail, dismiss
from announcements.views import CreateAnnouncementView, UpdateAnnouncementView
from announcements.views import DeleteAnnouncementView, AnnouncementListView

urlpatterns = patterns("",
    url(r"^$", AnnouncementListView.as_view(), name="announcements_list"),
    url(r"^announcement/create/$", CreateAnnouncementView.as_view(), name="announcements_create"),
    url(r"^announcement/(?P<pk>\d+)/$", detail, name="announcements_detail"),
    url(r"^announcement/(?P<pk>\d+)/hide/$", dismiss, name="announcements_dismiss"),
    url(r"^announcement/(?P<pk>\d+)/update/$", UpdateAnnouncementView.as_view(), name="announcements_update"),
    url(r"^announcement/(?P<pk>\d+)/delete/$", DeleteAnnouncementView.as_view(), name="announcements_delete"),
)
<|endoftext|>