<commit_before>import collections

import math
from django.db import models
from django.urls import reverse

import data.models

class AndalusianStyle(object):

    def get_style(self):
        return "andalusian"

    def get_object_map(self, key):
        return {"performance": InstrumentPerformance,
                "release": Album,
                "artist": Artist,
                "instrument": Instrument,
                "sectionperformance": InstrumentSectionPerformance,
                "orchestraperformer": OrchestraPerformer,
                "recording": Recording,
                "orchestra": Orchestra,
                "section": Section
                }[key]

class Orchestra(AndalusianStyle, data.models.BaseModel):
    class Meta:
        ordering = ['id']

    mbid = models.UUIDField(blank=True, null=True)
    name = models.CharField(max_length=255)
    transliterated_name = models.CharField(max_length=255, blank=True)
    group_members = models.ManyToManyField('Artist', blank=True, related_name='groups', through="OrchestraPerformer")

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        viewname = "%s-orchestra" % (self.get_style(), )
        return reverse(viewname, args=[self.mbid])

    def get_musicbrainz_url(self):
        return "http://musicbrainz.org/artist/%s" % self.mbid

    def performers(self):
        IPClass = self.get_object_map("orchestraperformer")
        performances = IPClass.objects.filter(orchestra=self)
        perfs = [p.performer for p in performances]
        return perfs

    def recordings(self):
        return self.recording_set.all()

class OrchestraAlias(models.Model):
    name = models.CharField(max_length=255)
    orchestra = models.ForeignKey("Orchestra", related_name="aliases", on_delete=models.CASCADE)

    def __str__(self):
        return self.name

class Artist(AndalusianStyle, data.models.BaseModel):
    class Meta:
        ordering = ['id']

    missing_image = "artist.jpg"

    GENDER_CHOICES = (
        ('M', 'Male'),
        ('F', 'Female')
    )
    name = models.CharField(max_length=200)
    transliterated_name = models.CharField(max_length=200, blank=True)
    mbid = models.UUIDField(blank=True, null=True)
    gender = models.CharField(max_length=1, choices=GENDER_CHOICES, blank=True, null=True)
    begin = models.CharField(max_length=10, blank=True, null=True)
    end = models.CharField(max_length=10, blank=True, null=True)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        viewname = "%s-artist" % (self.get_style(), )
        return reverse(viewname, args=[self.mbid])

    def get_musicbrainz_url(self):
        return "http://musicbrainz.org/artist/%s" % self.mbid

    def recordings(self):
        IPClass = self.get_object_map("performance")
        performances = IPClass.objects.filter(performer=self)
        recs = [p.recording for p in performances]
        return recs

    def performances(self, tab=[], nawba=[], mizan=[]):
        pass

    def instruments(self):
        insts = []
        for perf in self.instrumentperformance_set.all():
            if perf.instrument.name not in insts:
                insts.append(perf.instrument)
        if len(insts) > 0:
            return insts[0]
        return None

    def similar_artists(self):
        pass

    def collaborating_artists(self):
        # Get all recordings
        # For each artist on the recordings (both types), add a counter
        # top 10 artist ids + the recordings they collaborate on
        c = collections.Counter()
        recordings = collections.defaultdict(set)
        for recording in self.recordings():
            for p in recording.performers():
                if p.id != self.id:
                    recordings[p.id].add(recording)
                    c[p.id] += 1

        return [(Artist.objects.get(pk=pk), list(recordings[pk])) for pk, count in c.most_common()]

class ArtistAlias(data.models.ArtistAlias):
    pass

class AlbumRecording(models.Model):
    """ Links a album to a recording with an explicit ordering """
    album = models.ForeignKey('Album', on_delete=models.CASCADE)
    recording = models.ForeignKey('Recording', on_delete=models.CASCADE)
    # The number that the track comes in the album. Numerical 1-n
    track = models.IntegerField()

    class Meta:
        ordering = ("track", )

    def __str__(self):
        return u"%s: %s from %s" % (self.track, self.recording, self.album)

class Album(AndalusianStyle, data.models.BaseModel):
    class Meta:
        ordering = ['id']

    missing_image = "album.jpg"

    mbid = models.UUIDField(blank=True, null=True)
    title = models.CharField(max_length=255)
    transliterated_title = models.CharField(max_length=255, blank=True)
    artists = models.ManyToManyField('Orchestra')
    recordings = models.ManyToManyField('Recording', through="AlbumRecording")
    director = models.ForeignKey('Artist', null=True, on_delete=models.CASCADE)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        viewname = "%s-album" % (self.get_style(), )
        return reverse(viewname, args=[self.mbid])

    def get_musicbrainz_url(self):
        return "http://musicbrainz.org/release/%s" % self.mbid

class Work(AndalusianStyle, data.models.BaseModel):
    class Meta:
        ordering = ['id']

    mbid = models.UUIDField(blank=True, null=True)
    title = models.CharField(max_length=255)
    transliterated_title = models.CharField(max_length=255, blank=True)

    def __str__(self):
        return self.title

class Genre(AndalusianStyle, data.models.BaseModel):
    class Meta:
        ordering = ['id']

    name = models.CharField(max_length=100, blank=True)
    transliterated_name = models.CharField(max_length=100, blank=True)

    def __str__(self):
        return self.name

class RecordingWork(models.Model):
    work = models.ForeignKey('Work', on_delete=models.CASCADE)
    recording = models.ForeignKey('Recording', on_delete=models.CASCADE)
    sequence = models.IntegerField()

    class Meta:
        ordering = ("sequence", )

    def __str__(self):
        return u"%s: %s" % (self.sequence, self.work.title)

class Recording(AndalusianStyle, data.models.BaseModel):
    class Meta:
        ordering = ['id']

    mbid = models.UUIDField(blank=True, null=True)
    works = models.ManyToManyField("Work", through="RecordingWork")
    artists = models.ManyToManyField("Artist", through="InstrumentPerformance")
    title = models.CharField(max_length=255)
    transliterated_title = models.CharField(max_length=255, blank=True)
    length = models.IntegerField(blank=True, null=True)
    year = models.IntegerField(blank=True, null=True)
    genre = models.ForeignKey('Genre', null=True, on_delete=models.CASCADE)
    archive_url = models.CharField(max_length=255)
    musescore_url = models.CharField(max_length=255)
    poems = models.ManyToManyField("Poem", through="RecordingPoem")

    def __str__(self):
        return u"%s" % self.title

    def performers(self):
        return self.artists.all()

    def length_format(self):
        numsecs = self.length / 1000
        minutes = math.floor(numsecs / 60.0)
        hours = math.floor(minutes / 60.0)
        minutes = math.floor(minutes - hours * 60)
        seconds = math.floor(numsecs - hours * 3600 - minutes * 60)
        if hours:
            val = "%02d:%02d:%02d" % (hours, minutes, seconds)
        else:
            val = "%02d:%02d" % (minutes, seconds)
        return val

    def get_dict(self):
        release = self.album_set.first()
        title = None
        if release:
            title = release.title
        image = "/media/images/noconcert.jpg"
        artists = self.artists.values_list('name').all()[:3]
        return {
                "concert": title,
                "mainArtists": [item for sublist in artists for item in sublist],
                "name": self.title,
                "image": image,
                "linkToRecording": reverse("andalusian-recording", args=[self.mbid]),
                "collaborators": [],
                "selectedArtists": ""
        }

class Instrument(AndalusianStyle, data.models.BaseModel):
    class Meta:
        ordering = ['id']

    percussion = models.BooleanField(default=False)
    name = models.CharField(max_length=50)
    mbid = models.UUIDField(blank=True, null=True)

    def __str__(self):
        return self.name

class InstrumentPerformance(models.Model):
    recording = models.ForeignKey('Recording', on_delete=models.CASCADE)
    performer = models.ForeignKey('Artist', on_delete=models.CASCADE)
    instrument = models.ForeignKey('Instrument', on_delete=models.CASCADE)
    lead = models.BooleanField(default=False)

    def __str__(self):
        return u"%s playing %s on %s" % (self.performer, self.instrument, self.recording)

class OrchestraPerformer(models.Model):
    orchestra = models.ForeignKey('Orchestra', on_delete=models.CASCADE)
    performer = models.ForeignKey('Artist', on_delete=models.CASCADE)
    instruments = models.ManyToManyField('Instrument')
    director = models.BooleanField(default=False)
    begin = models.CharField(max_length=10, blank=True, null=True)
    end = models.CharField(max_length=10, blank=True, null=True)

    def __str__(self):
        ret = u"%s played %s on %s" % (self.performer, u", ".join([str(i) for i in self.instruments.all()]), self.orchestra)
        if self.director:
            ret += u". Moreover, %s acted as the director of this orchestra" % self.performer
            if self.begin:
                ret += u" from %s" % self.begin
            if self.end:
                ret += u" until %s" % self.end
        return ret

class Tab(data.models.BaseModel):
    class Meta:
        ordering = ['display_order', 'id']

    uuid = models.UUIDField(db_index=True, null=True)
    name = models.TextField()
    transliterated_name = models.TextField()

    # Set to 1 to force some Tab to show at the bottom when listing them
    display_order = models.IntegerField(null=False, default=0)

    def __str__(self):
        return self.name

class Nawba(data.models.BaseModel):
    class Meta:
        ordering = ['display_order', 'id']

    uuid = models.UUIDField(db_index=True, null=True)
    name = models.TextField()
    transliterated_name = models.TextField()

    # Set to 1 to force some Nawba to show at the bottom when listing them
    display_order = models.IntegerField(null=False, default=0)

    def __str__(self):
        return self.name

class Mizan(data.models.BaseModel):
    class Meta:
        ordering = ['display_order', 'id']

    uuid = models.UUIDField(db_index=True, null=True)
    name = models.TextField()
    transliterated_name = models.TextField()

    # Set to 1 to force some Mizan to show at the bottom when listing them
    display_order = models.IntegerField(null=False, default=0)

    def __str__(self):
        return self.name

class Form(data.models.BaseModel):
    class Meta:
        ordering = ['display_order', 'id']

    uuid = models.UUIDField(db_index=True, null=True)
    name = models.TextField()
    transliterated_name = models.TextField()

    # Set to 1 to force some Form to show at the bottom when listing them
    display_order = models.IntegerField(null=False, default=0)

    def __str__(self):
        return self.name

class Section(AndalusianStyle, data.models.BaseModel):
    recording = models.ForeignKey('Recording', on_delete=models.CASCADE)
    start_time = models.TimeField(blank=True, null=True)
    end_time = models.TimeField(blank=True, null=True)
    tab = models.ForeignKey('Tab', blank=True, null=True, on_delete=models.CASCADE)
    nawba = models.ForeignKey('Nawba', blank=True, null=True, on_delete=models.CASCADE)
    mizan = models.ForeignKey('Mizan', blank=True, null=True, on_delete=models.CASCADE)
    form = models.ForeignKey('Form', blank=True, null=True, on_delete=models.CASCADE)

    def __str__(self):
        return u"Section of %s (from %s to %s), a %s from mizan %s of tab' %s, nawba %s" % \
               (self.recording, self.start_time, self.end_time,
                self.form, self.mizan, self.tab, self.nawba)

class InstrumentSectionPerformance(models.Model):
    section = models.ForeignKey('Section', on_delete=models.CASCADE)
    performer = models.ForeignKey('Artist', on_delete=models.CASCADE)
    instrument = models.ForeignKey('Instrument', on_delete=models.CASCADE)
    lead = models.BooleanField(default=False)

    def __str__(self):
        return u"%s playing %s on section (%s, %s) of recording %s" % \
               (self.performer, self.instrument, self.section.start_time, self.section.end_time, self.section.recording)

class Sanaa(data.models.BaseModel):
    class Meta:
        ordering = ['id']

    title = models.CharField(max_length=255)
    transliterated_title = models.CharField(max_length=255, blank=True)

    def __str__(self):
        return self.title

class PoemType(models.Model):
    type = models.CharField(max_length=50)

    def __str__(self):
        return self.type

class Poem(data.models.BaseModel):
    class Meta:
        ordering = ['id']

    identifier = models.CharField(max_length=100, blank=True, null=True)
    first_words = models.CharField(max_length=255, blank=True, null=True)
    transliterated_first_words = models.CharField(max_length=255, blank=True, null=True)
    type = models.ForeignKey(PoemType, blank=True, null=True, on_delete=models.CASCADE)
    text = models.TextField()
    transliterated_text = models.TextField(blank=True)
    title = models.CharField(max_length=255, blank=True, null=True)
    transliterated_title = models.CharField(max_length=255, blank=True, null=True)

    def __str__(self):
        return self.identifier

class RecordingPoem(models.Model):
    recording = models.ForeignKey('Recording', on_delete=models.CASCADE)
    poem = models.ForeignKey('Poem', on_delete=models.CASCADE)
    order_number = models.IntegerField(blank=True, null=True)
<commit_msg>Use natural keys for andalusian recordings<commit_after>import collections

import math
from django.db import models
from django.urls import reverse

import data.models

class AndalusianStyle(object):

    def get_style(self):
        return "andalusian"

    def get_object_map(self, key):
        return {"performance": InstrumentPerformance,
                "release": Album,
                "artist": Artist,
                "instrument": Instrument,
                "sectionperformance": InstrumentSectionPerformance,
                "orchestraperformer": OrchestraPerformer,
                "recording": Recording,
                "orchestra": Orchestra,
                "section": Section
                }[key]

class Orchestra(AndalusianStyle, data.models.BaseModel):
    class Meta:
        ordering = ['id']

    mbid = models.UUIDField(blank=True, null=True)
    name = models.CharField(max_length=255)
    transliterated_name = models.CharField(max_length=255, blank=True)
    group_members = models.ManyToManyField('Artist', blank=True, related_name='groups', through="OrchestraPerformer")

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        viewname = "%s-orchestra" % (self.get_style(), )
        return reverse(viewname, args=[self.mbid])

    def get_musicbrainz_url(self):
        return "http://musicbrainz.org/artist/%s" % self.mbid

    def performers(self):
        IPClass = self.get_object_map("orchestraperformer")
        performances = IPClass.objects.filter(orchestra=self)
        perfs = [p.performer for p in performances]
        return perfs

    def recordings(self):
        return self.recording_set.all()

class OrchestraAlias(models.Model):
    name = models.CharField(max_length=255)
    orchestra = models.ForeignKey("Orchestra", related_name="aliases", on_delete=models.CASCADE)

    def __str__(self):
        return self.name

class Artist(AndalusianStyle, data.models.BaseModel):
    class Meta:
        ordering = ['id']

    missing_image = "artist.jpg"

    GENDER_CHOICES = (
        ('M', 'Male'),
        ('F', 'Female')
    )
    name = models.CharField(max_length=200)
    transliterated_name = models.CharField(max_length=200, blank=True)
    mbid = models.UUIDField(blank=True, null=True)
    gender = models.CharField(max_length=1, choices=GENDER_CHOICES, blank=True, null=True)
    begin = models.CharField(max_length=10, blank=True, null=True)
    end = models.CharField(max_length=10, blank=True, null=True)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        viewname = "%s-artist" % (self.get_style(), )
        return reverse(viewname, args=[self.mbid])

    def get_musicbrainz_url(self):
        return "http://musicbrainz.org/artist/%s" % self.mbid

    def recordings(self):
        IPClass = self.get_object_map("performance")
        performances = IPClass.objects.filter(performer=self)
        recs = [p.recording for p in performances]
        return recs

    def performances(self, tab=[], nawba=[], mizan=[]):
        pass

    def instruments(self):
        insts = []
        for perf in self.instrumentperformance_set.all():
            if perf.instrument.name not in insts:
                insts.append(perf.instrument)
        if len(insts) > 0:
            return insts[0]
        return None

    def similar_artists(self):
        pass

    def collaborating_artists(self):
        # Get all recordings
        # For each artist on the recordings (both types), add a counter
        # top 10 artist ids + the recordings they collaborate on
        c = collections.Counter()
        recordings = collections.defaultdict(set)
        for recording in self.recordings():
            for p in recording.performers():
                if p.id != self.id:
                    recordings[p.id].add(recording)
                    c[p.id] += 1

        return [(Artist.objects.get(pk=pk), list(recordings[pk])) for pk, count in c.most_common()]

class ArtistAlias(data.models.ArtistAlias):
    pass

class AlbumRecording(models.Model):
    """ Links a album to a recording with an explicit ordering """
    album = models.ForeignKey('Album', on_delete=models.CASCADE)
    recording = models.ForeignKey('Recording', on_delete=models.CASCADE)
    # The number that the track comes in the album. Numerical 1-n
    track = models.IntegerField()

    class Meta:
        ordering = ("track", )

    def __str__(self):
        return u"%s: %s from %s" % (self.track, self.recording, self.album)

class Album(AndalusianStyle, data.models.BaseModel):
    class Meta:
        ordering = ['id']

    missing_image = "album.jpg"

    mbid = models.UUIDField(blank=True, null=True)
    title = models.CharField(max_length=255)
    transliterated_title = models.CharField(max_length=255, blank=True)
    artists = models.ManyToManyField('Orchestra')
    recordings = models.ManyToManyField('Recording', through="AlbumRecording")
    director = models.ForeignKey('Artist', null=True, on_delete=models.CASCADE)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        viewname = "%s-album" % (self.get_style(), )
        return reverse(viewname, args=[self.mbid])

    def get_musicbrainz_url(self):
        return "http://musicbrainz.org/release/%s" % self.mbid

class Work(AndalusianStyle, data.models.BaseModel):
    class Meta:
        ordering = ['id']

    mbid = models.UUIDField(blank=True, null=True)
    title = models.CharField(max_length=255)
    transliterated_title = models.CharField(max_length=255, blank=True)

    def __str__(self):
        return self.title

class Genre(AndalusianStyle, data.models.BaseModel):
    class Meta:
        ordering = ['id']

    name = models.CharField(max_length=100, blank=True)
    transliterated_name = models.CharField(max_length=100, blank=True)

    def __str__(self):
        return self.name

class RecordingWork(models.Model):
    work = models.ForeignKey('Work', on_delete=models.CASCADE)
    recording = models.ForeignKey('Recording', on_delete=models.CASCADE)
    sequence = models.IntegerField()

    class Meta:
        ordering = ("sequence", )

    def __str__(self):
        return u"%s: %s" % (self.sequence, self.work.title)

class RecordingManager(models.Manager):
    def get_by_natural_key(self, mbid):
        return self.get(mbid=mbid)

class Recording(AndalusianStyle, data.models.BaseModel):
    class Meta:
        ordering = ['id']

    mbid = models.UUIDField(blank=True, null=True)
    works = models.ManyToManyField("Work", through="RecordingWork")
    artists = models.ManyToManyField("Artist", through="InstrumentPerformance")
    title = models.CharField(max_length=255)
    transliterated_title = models.CharField(max_length=255, blank=True)
    length = models.IntegerField(blank=True, null=True)
    year = models.IntegerField(blank=True, null=True)
    genre = models.ForeignKey('Genre', null=True, on_delete=models.CASCADE)
    archive_url = models.CharField(max_length=255)
    musescore_url = models.CharField(max_length=255)
    poems = models.ManyToManyField("Poem", through="RecordingPoem")

    objects = RecordingManager()

    def natural_key(self):
        return self.mbid

    def __str__(self):
        return u"%s" % self.title

    def performers(self):
        return self.artists.all()

    def length_format(self):
        numsecs = self.length / 1000
        minutes = math.floor(numsecs / 60.0)
        hours = math.floor(minutes / 60.0)
        minutes = math.floor(minutes - hours * 60)
        seconds = math.floor(numsecs - hours * 3600 - minutes * 60)
        if hours:
            val = "%02d:%02d:%02d" % (hours, minutes, seconds)
        else:
            val = "%02d:%02d" % (minutes, seconds)
        return val

    def get_dict(self):
        release = self.album_set.first()
        title = None
        if release:
            title = release.title
        image = "/media/images/noconcert.jpg"
        artists = self.artists.values_list('name').all()[:3]
        return {
                "concert": title,
                "mainArtists": [item for sublist in artists for item in sublist],
                "name": self.title,
                "image": image,
                "linkToRecording": reverse("andalusian-recording", args=[self.mbid]),
                "collaborators": [],
                "selectedArtists": ""
        }

class Instrument(AndalusianStyle, data.models.BaseModel):
    class Meta:
        ordering = ['id']

    percussion = models.BooleanField(default=False)
    name = models.CharField(max_length=50)
    mbid = models.UUIDField(blank=True, null=True)

    def __str__(self):
        return self.name

class InstrumentPerformance(models.Model):
    recording = models.ForeignKey('Recording', on_delete=models.CASCADE)
    performer = models.ForeignKey('Artist', on_delete=models.CASCADE)
    instrument = models.ForeignKey('Instrument', on_delete=models.CASCADE)
    lead = models.BooleanField(default=False)

    def __str__(self):
        return u"%s playing %s on %s" % (self.performer, self.instrument, self.recording)

class OrchestraPerformer(models.Model):
    orchestra = models.ForeignKey('Orchestra', on_delete=models.CASCADE)
    performer = models.ForeignKey('Artist', on_delete=models.CASCADE)
    instruments = models.ManyToManyField('Instrument')
    director = models.BooleanField(default=False)
    begin = models.CharField(max_length=10, blank=True, null=True)
    end = models.CharField(max_length=10, blank=True, null=True)

    def __str__(self):
        ret = u"%s played %s on %s" % (self.performer, u", ".join([str(i) for i in self.instruments.all()]), self.orchestra)
        if self.director:
            ret += u". Moreover, %s acted as the director of this orchestra" % self.performer
            if self.begin:
                ret += u" from %s" % self.begin
            if self.end:
                ret += u" until %s" % self.end
        return ret

class Tab(data.models.BaseModel):
    class Meta:
        ordering = ['display_order', 'id']

    uuid = models.UUIDField(db_index=True, null=True)
    name = models.TextField()
    transliterated_name = models.TextField()

    # Set to 1 to force some Tab to show at the bottom when listing them
    display_order = models.IntegerField(null=False, default=0)

    def __str__(self):
        return self.name

class Nawba(data.models.BaseModel):
    class Meta:
        ordering = ['display_order', 'id']

    uuid = models.UUIDField(db_index=True, null=True)
    name = models.TextField()
    transliterated_name = models.TextField()

    # Set to 1 to force some Nawba to show at the bottom when listing them
    display_order = models.IntegerField(null=False, default=0)

    def __str__(self):
        return self.name

class Mizan(data.models.BaseModel):
    class Meta:
        ordering = ['display_order', 'id']

    uuid = models.UUIDField(db_index=True, null=True)
    name = models.TextField()
    transliterated_name = models.TextField()

    # Set to 1 to force some Mizan to show at the bottom when listing them
    display_order = models.IntegerField(null=False, default=0)

    def __str__(self):
        return self.name

class Form(data.models.BaseModel):
    class Meta:
        ordering = ['display_order', 'id']

    uuid = models.UUIDField(db_index=True, null=True)
    name = models.TextField()
    transliterated_name = models.TextField()

    # Set to 1 to force some Form to show at the bottom when listing them
    display_order = models.IntegerField(null=False, default=0)

    def __str__(self):
        return self.name

class Section(AndalusianStyle, data.models.BaseModel):
    recording = models.ForeignKey('Recording', on_delete=models.CASCADE)
    start_time = models.TimeField(blank=True, null=True)
    end_time = models.TimeField(blank=True, null=True)
    tab = models.ForeignKey('Tab', blank=True, null=True, on_delete=models.CASCADE)
    nawba = models.ForeignKey('Nawba', blank=True, null=True, on_delete=models.CASCADE)
    mizan = models.ForeignKey('Mizan', blank=True, null=True, on_delete=models.CASCADE)
    form = models.ForeignKey('Form', blank=True, null=True, on_delete=models.CASCADE)

    def __str__(self):
        return u"Section of %s (from %s to %s), a %s from mizan %s of tab' %s, nawba %s" % \
               (self.recording, self.start_time, self.end_time,
                self.form, self.mizan, self.tab, self.nawba)

class InstrumentSectionPerformance(models.Model):
    section = models.ForeignKey('Section', on_delete=models.CASCADE)
    performer = models.ForeignKey('Artist', on_delete=models.CASCADE)
    instrument = models.ForeignKey('Instrument', on_delete=models.CASCADE)
    lead = models.BooleanField(default=False)

    def __str__(self):
        return u"%s playing %s on section (%s, %s) of recording %s" % \
               (self.performer, self.instrument, self.section.start_time, self.section.end_time, self.section.recording)

class Sanaa(data.models.BaseModel):
    class Meta:
        ordering = ['id']

    title = models.CharField(max_length=255)
    transliterated_title = models.CharField(max_length=255, blank=True)

    def __str__(self):
        return self.title

class PoemType(models.Model):
    type = models.CharField(max_length=50)

    def __str__(self):
        return self.type

class Poem(data.models.BaseModel):
    class Meta:
        ordering = ['id']

    identifier = models.CharField(max_length=100, blank=True, null=True)
    first_words = models.CharField(max_length=255, blank=True, null=True)
    transliterated_first_words = models.CharField(max_length=255, blank=True, null=True)
    type = models.ForeignKey(PoemType, blank=True, null=True, on_delete=models.CASCADE)
    text = models.TextField()
    transliterated_text = models.TextField(blank=True)
    title = models.CharField(max_length=255, blank=True, null=True)
    transliterated_title = models.CharField(max_length=255, blank=True, null=True)

    def __str__(self):
        return self.identifier

class RecordingPoem(models.Model):
    recording = models.ForeignKey('Recording', on_delete=models.CASCADE)
    poem = models.ForeignKey('Poem', on_delete=models.CASCADE)
    order_number = models.IntegerField(blank=True, null=True)
<|endoftext|>


<commit_before>#!/usr/bin/env python
"""
Usage:
    json2csv.py --ons <files>...
"""

from __future__ import absolute_import, print_function, division
from docopt import docopt
import json
import re
from utf8csv import UnicodeWriter

### options
options = docopt(__doc__)
files = options['<files>']
if options['--ons']:
    pass

filename = files[0]

with open(filename, "r") as f:
    data = json.load(f)
print(j)

#with open(filename, V"w") as f:
#    csvout = UnicodeWriter(f)

def ons_rename_headers(data):
    for row in data:
        for i, name in []:
            pass
<commit_msg>Remove json2csv<commit_after><|endoftext|>


<commit_before>import sys

# import editor
from floo.common.handlers import floo_handler
from floo.common import msg, utils, shared as G

class AgentConnection(floo_handler.FlooHandler):

    def __init__(self, owner, workspace, emacs_handler, get_bufs=True):
        super(AgentConnection, self).__init__(owner, workspace, get_bufs)
        self.emacs_handler = emacs_handler
        if sys.version_info[0] == 2 and sys.version_info[1] == 6:
            # Work around http://bugs.python.org/issue11326
            msg.error('Disabling SSL to work around a bug in Python 2.6. Please upgrade your Python to get SSL. See http://bugs.python.org/issue11326')
            G.SECURE = False
            G.DEFAULT_PORT = 3148

    @property
    def client(self):
        return 'Emacs'

    def get_view(self, buf_id):
        return self.emacs_handler.get_view(buf_id)

    def _ok_cancel_dialog(self, prompt, cb):
        return self.emacs_handler.get_input(prompt, cb=lambda data: cb(data['response']), y_or_n=True)

    @utils.inlined_callbacks
    def ok_cancel_dialog(self, prompt):
        retval = yield self._ok_cancel_dialog, prompt
        utils.return_value(retval)

    def to_emacs(self, name, data):
        data['name'] = name
        self.emacs_handler.send(data)

    def _on_room_info(self, data):
        super(AgentConnection, self)._on_room_info(data)
        # data['project_path'] = G.PROJECT_PATH
        self.to_emacs('room_info', {
            'perms': data['perms'],
            'project_path': G.PROJECT_PATH,
            'workspace_name': data['room_name'],
        })

    def _on_create_buf(self, data):
        super(AgentConnection, self)._on_create_buf(data)
        self.to_emacs('create_buf', {
            'full_path': utils.get_full_path(data['path']),
            'path': data['path'],
            'username': data.get('username', ''),
        })

    def _on_delete_buf(self, data):
        buf_id = int(data['id'])
        buf = self.bufs[buf_id]
        path = buf['path']
        try:
            super(AgentConnection, self)._on_delete_buf(data)
        except Exception as e:
            msg.debug('Unable to delete buf %s: %s' % (path, str(e)))
        else:
            self.to_emacs('delete_buf', {
                'full_path': utils.get_full_path(path),
                'path': path,
                'username': data.get('username', ''),
            })

    def _on_rename_buf(self, data):
        buf = self.bufs[int(data['id'])]
        # This can screw up if someone else renames the buffer around the same time as us. Oh well.
        buf = self.get_buf_by_path(utils.get_full_path(data['path']))
        if not buf:
            return super(AgentConnection, self)._on_rename_buf(data)
        msg.debug('We already renamed %s. Skipping' % buf['path'])

    def _on_highlight(self, data):
        super(AgentConnection, self)._on_highlight(data)
        buf = self.bufs[data['id']]
        # TODO: save highlights for when user opens the buffer in emacs
        self.to_emacs('highlight', {
            'id': buf['id'],
            'full_path': utils.get_full_path(buf['path']),
            'ranges': data['ranges'],
            'user_id': data['user_id'],
            'username': data.get('username', 'unknown user'),
        })

    def _on_msg(self, data):
        msg.log('msg')
<commit_msg>make more privater<commit_after>import sys

# import editor
from floo.common.handlers import floo_handler
from floo.common import msg, utils, shared as G

class AgentConnection(floo_handler.FlooHandler):

    def __init__(self, owner, workspace, emacs_handler, get_bufs=True):
        super(AgentConnection, self).__init__(owner, workspace, get_bufs)
        self.emacs_handler = emacs_handler
        if sys.version_info[0] == 2 and sys.version_info[1] == 6:
            # Work around http://bugs.python.org/issue11326
            msg.error('Disabling SSL to work around a bug in Python 2.6. Please upgrade your Python to get SSL. See http://bugs.python.org/issue11326')
            G.SECURE = False
            G.DEFAULT_PORT = 3148

    @property
    def client(self):
        return 'Emacs'

    def get_view(self, buf_id):
        return self.emacs_handler.get_view(buf_id)

    def __ok_cancel_dialog(self, prompt, cb):
        return self.emacs_handler.get_input(prompt, cb=lambda data: cb(data['response']), y_or_n=True)

    @utils.inlined_callbacks
    def ok_cancel_dialog(self, prompt):
        retval = yield self.__ok_cancel_dialog, prompt
        utils.return_value(retval)

    def to_emacs(self, name, data):
        data['name'] = name
        self.emacs_handler.send(data)

    def _on_room_info(self, data):
        super(AgentConnection, self)._on_room_info(data)
        # data['project_path'] = G.PROJECT_PATH
        self.to_emacs('room_info', {
            'perms': data['perms'],
            'project_path': G.PROJECT_PATH,
            'workspace_name': data['room_name'],
        })

    def _on_create_buf(self, data):
        super(AgentConnection, self)._on_create_buf(data)
        self.to_emacs('create_buf', {
            'full_path': utils.get_full_path(data['path']),
            'path': data['path'],
            'username': data.get('username', ''),
        })

    def _on_delete_buf(self, data):
        buf_id = int(data['id'])
        buf = self.bufs[buf_id]
        path = buf['path']
        try:
            super(AgentConnection, self)._on_delete_buf(data)
        except Exception as e:
            msg.debug('Unable to delete buf %s: %s' % (path, str(e)))
        else:
            self.to_emacs('delete_buf', {
                'full_path': utils.get_full_path(path),
                'path': path,
                'username': data.get('username', ''),
            })

    def _on_rename_buf(self, data):
        buf = self.bufs[int(data['id'])]
        # This can screw up if someone else renames the buffer around the same time as us. Oh well.
        buf = self.get_buf_by_path(utils.get_full_path(data['path']))
        if not buf:
            return super(AgentConnection, self)._on_rename_buf(data)
        msg.debug('We already renamed %s. Skipping' % buf['path'])

    def _on_highlight(self, data):
        super(AgentConnection, self)._on_highlight(data)
        buf = self.bufs[data['id']]
        # TODO: save highlights for when user opens the buffer in emacs
        self.to_emacs('highlight', {
            'id': buf['id'],
            'full_path': utils.get_full_path(buf['path']),
            'ranges': data['ranges'],
            'user_id': data['user_id'],
            'username': data.get('username', 'unknown user'),
        })

    def _on_msg(self, data):
        msg.log('msg')
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author: oesteban
# @Date:   2015-11-19 16:44:27
# @Last Modified by:   oesteban
# @Last Modified time: 2016-10-05 15:03:18
"""
fMRI preprocessing workflow
=====
"""
from __future__ import absolute_import, division, print_function, unicode_literals

import os
import os.path as op
import glob
from argparse import ArgumentParser
from argparse import RawTextHelpFormatter
from multiprocessing import cpu_count

def main():
    """Entry point"""
    from fmriprep import __version__
    parser = ArgumentParser(description='fMRI Preprocessing workflow',
                            formatter_class=RawTextHelpFormatter)

    # Arguments as specified by BIDS-Apps
    # required, positional arguments
    # IMPORTANT: they must go directly with the parser object
    parser.add_argument('bids_dir', action='store', default=os.getcwd())
    parser.add_argument('output_dir', action='store',
                         default=op.join(os.getcwd(), 'out'))
    parser.add_argument('analysis_level', choices=['participant'])

    # optional arguments
    parser.add_argument('--participant_label', action='store', nargs='+')
    parser.add_argument('-v', '--version', action='version',
                         version='fmriprep v{}'.format(__version__))

    # Other options
    g_input = parser.add_argument_group('fMRIprep specific arguments')
    g_input.add_argument('-s', '--session-id', action='store', default='single_session')
    g_input.add_argument('-r', '--run-id', action='store', default='single_run')
    g_input.add_argument('-d', '--data-type', action='store', choices=['anat', 'func'])
    g_input.add_argument('--debug', action='store_true', default=False,
                         help='run debug version of workflow')
    g_input.add_argument('--nthreads', action='store', default=0,
                         type=int, help='number of threads')
    g_input.add_argument('--write-graph', action='store_true', default=False,
                         help='Write workflow graph.')
    g_input.add_argument('--use-plugin', action='store', default=None,
                         help='nipype plugin configuration file')
    g_input.add_argument('-w', '--work-dir', action='store',
                           default=op.join(os.getcwd(), 'work'))
    g_input.add_argument('-t', '--workflow-type', default='ds005', required=False,
                         action='store', choices=['ds005', 'ds054', 'HPC', 'spiral'],
                         help='workflow type, a monkeypatch while it is not automatically identified')

    # ANTs options
    g_ants = parser.add_argument_group('specific settings for ANTs registrations')
    g_ants.add_argument('--ants-nthreads', action='store', type=int,
                        help='number of threads that will be set in ANTs processes')
    g_ants.add_argument('--skull-strip-ants', action='store_true', default=False,
                         help='use ANTs-based skull-stripping')

    opts = parser.parse_args()
    create_workflow(opts)

def create_workflow(opts):
    import logging
    from nipype import config as ncfg
    from fmriprep.utils import make_folder
    from fmriprep.viz.reports import run_reports
    from fmriprep.workflows import base as fwb
    from fmriprep.workflows.base import base_workflow_enumerator

    settings = {
        'bids_root': op.abspath(opts.bids_dir),
        'write_graph': opts.write_graph,
        'nthreads': opts.nthreads,
        'debug': opts.debug,
        'skull_strip_ants': opts.skull_strip_ants,
        'output_dir': op.abspath(opts.output_dir),
        'work_dir': op.abspath(opts.work_dir)
    }

    # set up logger
    logger = logging.getLogger('cli')

    if opts.debug:
        settings['ants_t1-mni_settings'] = 't1-mni_registration_test'
        logger.setLevel(logging.DEBUG)

    if opts.ants_nthreads is not None:
        settings['ants_threads'] = opts.ants_nthreads

    log_dir = op.join(settings['output_dir'], 'log')
    derivatives = op.join(settings['output_dir'], 'derivatives')

    # Check and create output and working directories
    # Using make_folder to prevent https://github.com/poldracklab/mriqc/issues/111
    make_folder(settings['output_dir'])
    make_folder(settings['work_dir'])
    make_folder(derivatives)
    make_folder(log_dir)

    logger.addHandler(logging.FileHandler(op.join(log_dir, 'run_workflow')))

    # Set nipype config
    ncfg.update_config({
        'logging': {'log_directory': log_dir, 'log_to_file': True},
        'execution': {'crashdump_dir': log_dir}
    })

    # nipype plugin configuration
    plugin_settings = {'plugin': 'Linear'}
    if opts.use_plugin is not None:
        from yaml import load as loadyml
        with open(opts.use_plugin) as f:
            plugin_settings = loadyml(f)
    else:
        # Setup multiprocessing
        if settings['nthreads'] == 0:
            settings['nthreads'] = cpu_count()

        if settings['nthreads'] > 1:
            plugin_settings['plugin'] = 'MultiProc'
            plugin_settings['plugin_args'] = {'n_procs': settings['nthreads']}

    # Determine subjects to be processed
    subject_list = opts.participant_label

    if subject_list is None or not subject_list:
        subject_list = [op.basename(subdir)[4:] for subdir in glob.glob(
            op.join(settings['bids_root'], 'sub-*'))]

    logger.info('Subject list: %s', ', '.join(subject_list))

    # Build main workflow and run
    preproc_wf = base_workflow_enumerator(subject_list, settings=settings)
    preproc_wf.base_dir = settings['work_dir']
    preproc_wf.run(**plugin_settings)

    if opts.write_graph:
        preproc_wf.write_graph()

    run_reports(settings['output_dir'])

if __name__ == '__main__':
    main()
<commit_msg>set remove unnecessary as False for the time being until html report output spec is removed<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author: oesteban
# @Date:   2015-11-19 16:44:27
# @Last Modified by:   oesteban
# @Last Modified time: 2016-10-05 15:03:18
"""
fMRI preprocessing workflow
=====
"""
from __future__ import absolute_import, division, print_function, unicode_literals

import os
import os.path as op
import glob
from argparse import ArgumentParser
from argparse import RawTextHelpFormatter
from multiprocessing import cpu_count

def main():
    """Entry point"""
    from fmriprep import __version__
    parser = ArgumentParser(description='fMRI Preprocessing workflow',
                            formatter_class=RawTextHelpFormatter)

    # Arguments as specified by BIDS-Apps
    # required, positional arguments
    # IMPORTANT: they must go directly with the parser object
    parser.add_argument('bids_dir', action='store', default=os.getcwd())
    parser.add_argument('output_dir', action='store',
                         default=op.join(os.getcwd(), 'out'))
    parser.add_argument('analysis_level', choices=['participant'])

    # optional arguments
    parser.add_argument('--participant_label', action='store', nargs='+')
    parser.add_argument('-v', '--version', action='version',
                         version='fmriprep v{}'.format(__version__))

    # Other options
    g_input = parser.add_argument_group('fMRIprep specific arguments')
    g_input.add_argument('-s', '--session-id', action='store', default='single_session')
    g_input.add_argument('-r', '--run-id', action='store', default='single_run')
    g_input.add_argument('-d', '--data-type', action='store', choices=['anat', 'func'])
    g_input.add_argument('--debug', action='store_true', default=False,
                         help='run debug version of workflow')
    g_input.add_argument('--nthreads', action='store', default=0,
                         type=int, help='number of threads')
    g_input.add_argument('--write-graph', action='store_true', default=False,
                         help='Write workflow graph.')
    g_input.add_argument('--use-plugin', action='store', default=None,
                         help='nipype plugin configuration file')
    g_input.add_argument('-w', '--work-dir', action='store',
                           default=op.join(os.getcwd(), 'work'))
    g_input.add_argument('-t', '--workflow-type', default='ds005', required=False,
                         action='store', choices=['ds005', 'ds054', 'HPC', 'spiral'],
                         help='workflow type, a monkeypatch while it is not automatically identified')

    # ANTs options
    g_ants = parser.add_argument_group('specific settings for ANTs registrations')
    g_ants.add_argument('--ants-nthreads', action='store', type=int,
                        help='number of threads that will be set in ANTs processes')
    g_ants.add_argument('--skull-strip-ants', action='store_true', default=False,
                         help='use ANTs-based skull-stripping')

    opts = parser.parse_args()
    create_workflow(opts)

def create_workflow(opts):
    import logging
    from nipype import config as ncfg
    from fmriprep.utils import make_folder
    from fmriprep.viz.reports import run_reports
    from fmriprep.workflows import base as fwb
    from fmriprep.workflows.base import base_workflow_enumerator

    settings = {
        'bids_root': op.abspath(opts.bids_dir),
        'write_graph': opts.write_graph,
        'nthreads': opts.nthreads,
        'debug': opts.debug,
        'skull_strip_ants': opts.skull_strip_ants,
        'output_dir': op.abspath(opts.output_dir),
        'work_dir': op.abspath(opts.work_dir),
        'remove_unnecessary_outputs': False
    }

    # set up logger
    logger = logging.getLogger('cli')

    if opts.debug:
        settings['ants_t1-mni_settings'] = 't1-mni_registration_test'
        logger.setLevel(logging.DEBUG)

    if opts.ants_nthreads is not None:
        settings['ants_threads'] = opts.ants_nthreads

    log_dir = op.join(settings['output_dir'], 'log')
    derivatives = op.join(settings['output_dir'], 'derivatives')

    # Check and create output and working directories
    # Using make_folder to prevent https://github.com/poldracklab/mriqc/issues/111
    make_folder(settings['output_dir'])
    make_folder(settings['work_dir'])
    make_folder(derivatives)
    make_folder(log_dir)

    logger.addHandler(logging.FileHandler(op.join(log_dir, 'run_workflow')))

    # Set nipype config
    ncfg.update_config({
        'logging': {'log_directory': log_dir, 'log_to_file': True},
        'execution': {'crashdump_dir': log_dir}
    })

    # nipype plugin configuration
    plugin_settings = {'plugin': 'Linear'}
    if opts.use_plugin is not None:
        from yaml import load as loadyml
        with open(opts.use_plugin) as f:
            plugin_settings = loadyml(f)
    else:
        # Setup multiprocessing
        if settings['nthreads'] == 0:
            settings['nthreads'] = cpu_count()

        if settings['nthreads'] > 1:
            plugin_settings['plugin'] = 'MultiProc'
            plugin_settings['plugin_args'] = {'n_procs': settings['nthreads']}

    # Determine subjects to be processed
    subject_list = opts.participant_label

    if subject_list is None or not subject_list:
        subject_list = [op.basename(subdir)[4:] for subdir in glob.glob(
            op.join(settings['bids_root'], 'sub-*'))]

    logger.info('Subject list: %s', ', '.join(subject_list))

    # Build main workflow and run
    preproc_wf = base_workflow_enumerator(subject_list, settings=settings)
    preproc_wf.base_dir = settings['work_dir']
    preproc_wf.run(**plugin_settings)

    if opts.write_graph:
        preproc_wf.write_graph()

    run_reports(settings['output_dir'])

if __name__ == '__main__':
    main()
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author: oesteban
# @Date:   2015-11-19 16:44:27
# @Last Modified by:   oesteban
# @Last Modified time: 2016-03-10 12:51:17

"""
fMRI preprocessing workflow
=====
"""
from argparse import ArgumentParser
from argparse import RawTextHelpFormatter
import os
import os.path as op
from multiprocessing import cpu_count

from mriqc.utils import gather_bids_data
from nipype import config as ncfg

from fmriprep.workflows import fmri_preprocess
from fmriprep.workflows.anatomical import t1w_preprocessing

__author__ = "Oscar Esteban"
__copyright__ = ("Copyright 2016, Center for Reproducible Neuroscience, "
                 "Stanford University")
__credits__ = "Oscar Esteban"
__license__ = "BSD"
__version__ = "0.0.1"
__maintainer__ = "Oscar Esteban"
__email__ = "code@oscaresteban.es"
__status__ = "Prototype"

def main():
    """Entry point"""
    parser = ArgumentParser(description='fMRI Preprocessing workflow',
                            formatter_class=RawTextHelpFormatter)

    g_input = parser.add_argument_group('Inputs')
    g_input.add_argument('-i', '--bids-root', action='store',
                         default=os.getcwd())
    g_input.add_argument('--nthreads', action='store', default=0,
                         type=int, help='number of threads')
    g_input.add_argument(
        "--write-graph", action='store_true', default=False,
        help="Write workflow graph.")
    g_input.add_argument(
        "--use-plugin", action='store', default=None,
        help='nipype plugin configuration file')

    g_outputs = parser.add_argument_group('Outputs')
    g_outputs.add_argument('-o', '--output-dir', action='store')
    g_outputs.add_argument('-w', '--work-dir', action='store')

    opts = parser.parse_args()

    settings = {'bids_root': op.abspath(opts.bids_root),
                'output_dir': os.getcwd(),
                'write_graph': opts.write_graph,
                'skip': [],
                'nthreads': opts.nthreads}

    if opts.output_dir:
        settings['output_dir'] = op.abspath(opts.output_dir)

    if not op.exists(settings['output_dir']):
        os.makedirs(settings['output_dir'])

    if opts.work_dir:
        settings['work_dir'] = op.abspath(opts.work_dir)

        log_dir = op.join(settings['work_dir'], 'log')
        if not op.exists(log_dir):
            os.makedirs(log_dir)

        # Set nipype config
        ncfg.update_config({
            'logging': {'log_directory': log_dir, 'log_to_file': True},
            'execution': {'crashdump_dir': log_dir}
        })

    plugin_settings = {'plugin': 'Linear'}
    if opts.use_plugin is not None:
        from yaml import load as loadyml
        with open(opts.use_plugin) as f:
            plugin_settings = loadyml(f)
    else:
        # Setup multiprocessing
        if settings['nthreads'] == 0:
            settings['nthreads'] = cpu_count()

        if settings['nthreads'] > 1:
            plugin_settings['plugin'] = 'MultiProc'
            plugin_settings['plugin_args'] = {'n_procs': settings['nthreads']}

    subjects = gather_bids_data(settings['bids_root'])

    if not any([len(subjects[k]) > 0 for k in subjects.keys()]):
        raise RuntimeError('No scans found in %s' % settings['bids_root'])

    #fmriwf = fmri_preprocess(subject_list=subjects, settings=settings)
    #fmriwf.run(**plugin_settings)
    t1w_preproc = t1w_preprocessing(settings=settings)
    t1w_preproc.inputs.inputnode.t1 = subjects['anat'][0][-1]
    t1w_preproc.run(**plugin_settings)

if __name__ == '__main__':
    main()
<commit_msg>updated call to collect bids data<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author: oesteban
# @Date:   2015-11-19 16:44:27
# @Last Modified by:   oesteban
# @Last Modified time: 2016-03-10 12:51:17

"""
fMRI preprocessing workflow
=====
"""
from argparse import ArgumentParser
from argparse import RawTextHelpFormatter
from multiprocessing import cpu_count
import os
import os.path as op

from nipype import config as ncfg

from fmriprep.workflows import fmri_preprocess
from fmriprep.workflows.anatomical import t1w_preprocessing
from fmriprep.utils.misc import collect_bids_data

__author__ = "Oscar Esteban"
__copyright__ = ("Copyright 2016, Center for Reproducible Neuroscience, "
                 "Stanford University")
__credits__ = "Oscar Esteban"
__license__ = "BSD"
__version__ = "0.0.1"
__maintainer__ = "Oscar Esteban"
__email__ = "code@oscaresteban.es"
__status__ = "Prototype"

def main():
    """Entry point"""
    parser = ArgumentParser(description='fMRI Preprocessing workflow',
                            formatter_class=RawTextHelpFormatter)

    g_input = parser.add_argument_group('Inputs')
    g_input.add_argument('-i', '--bids-root', action='store',
                         default=os.getcwd())
    g_input.add_argument('--nthreads', action='store', default=0,
                         type=int, help='number of threads')
    g_input.add_argument(
        "--write-graph", action='store_true', default=False,
        help="Write workflow graph.")
    g_input.add_argument(
        "--use-plugin", action='store', default=None,
        help='nipype plugin configuration file')

    g_outputs = parser.add_argument_group('Outputs')
    g_outputs.add_argument('-o', '--output-dir', action='store')
    g_outputs.add_argument('-w', '--work-dir', action='store')

    opts = parser.parse_args()

    settings = {'bids_root': op.abspath(opts.bids_root),
                'output_dir': os.getcwd(),
                'write_graph': opts.write_graph,
                'skip': [],
                'nthreads': opts.nthreads}

    if opts.output_dir:
        settings['output_dir'] = op.abspath(opts.output_dir)

    if not op.exists(settings['output_dir']):
        os.makedirs(settings['output_dir'])

    if opts.work_dir:
        settings['work_dir'] = op.abspath(opts.work_dir)

        log_dir = op.join(settings['work_dir'], 'log')
        if not op.exists(log_dir):
            os.makedirs(log_dir)

        # Set nipype config
        ncfg.update_config({
            'logging': {'log_directory': log_dir, 'log_to_file': True},
            'execution': {'crashdump_dir': log_dir}
        })

    plugin_settings = {'plugin': 'Linear'}
    if opts.use_plugin is not None:
        from yaml import load as loadyml
        with open(opts.use_plugin) as f:
            plugin_settings = loadyml(f)
    else:
        # Setup multiprocessing
        if settings['nthreads'] == 0:
            settings['nthreads'] = cpu_count()

        if settings['nthreads'] > 1:
            plugin_settings['plugin'] = 'MultiProc'
            plugin_settings['plugin_args'] = {'n_procs': settings['nthreads']}

    subjects = collect_bids_data(settings['bids_root'])

    if not any([len(subjects[k]) > 0 for k in subjects.keys()]):
        raise RuntimeError('No scans found in %s' % settings['bids_root'])

    fmriwf = fmri_preprocess(subject_list=subjects, settings=settings)
    fmriwf.run(**plugin_settings)

if __name__ == '__main__':
    main()
<|endoftext|>


<commit_before>
from algoliasearch_django import AlgoliaIndex, register

from course_discovery.apps.course_metadata.algolia_proxy_models import (
    AlgoliaProxyCourse, AlgoliaProxyProduct, AlgoliaProxyProgram
)

class ProductIndex(AlgoliaIndex):
    search_fields = (('partner_names', 'partner'), ('product_title', 'title'), 'primary_description',
                     'secondary_description', 'tertiary_description')
    facet_fields = (('availability_level', 'availability'), ('subject_names', 'subject'), ('levels', 'level'),
                    ('active_languages', 'language'), ('product_type', 'product'), ('program_types', 'program_type'))
    ranking_fields = ('availability_rank', ('product_recent_enrollment_count', 'recent_enrollment_count'))
    result_fields = (('product_marketing_url', 'marketing_url'), ('product_card_image_url', 'card_image_url'),
                     ('product_uuid', 'uuid'), 'active_run_key', 'active_run_start', 'active_run_type', 'owners',
                     'course_titles')
    # Algolia needs this
    object_id_field = (('custom_object_id', 'objectID'), )
    fields = search_fields + facet_fields + ranking_fields + result_fields + object_id_field
    settings = {
        'searchableAttributes': [
            'unordered(title)',  # AG best practice: position of the search term in plain text fields doesn't matter
            'unordered(primary_description)',
            'unordered(secondary_description)',
            'unordered(tertiary_description)',
            'partner'
        ],
        'attributesForFaceting': ['partner', 'availability', 'subject', 'level', 'language', 'product', 'program_type'],
        'customRanking': ['asc(availability_rank)', 'desc(recent_enrollment_count)']
    }
    index_name = 'product'
    should_index = 'should_index'

    # Bit of a hack: Override get_queryset to return all wrapped versions of all courses and programs rather than an
    # actual queryset to get around the fact that courses and programs have different fields and therefore cannot be
    # combined in a union of querysets. AlgoliaIndex only uses get_queryset as an iterable, so an array works as well.
    def get_queryset(self):  # pragma: no cover
        qs1 = [AlgoliaProxyProduct(course) for course in AlgoliaProxyCourse.objects.all()]
        qs2 = [AlgoliaProxyProduct(program) for program in AlgoliaProxyProgram.objects.all()]
        return qs1 + qs2

class SpanishProductIndex(AlgoliaIndex):
    search_fields = (('partner_names', 'partner'), ('product_title', 'title'), 'primary_description',
                     'secondary_description', 'tertiary_description')
    facet_fields = (('availability_level', 'availability'), ('subject_names', 'subject'), ('levels', 'level'),
                    ('active_languages', 'language'), ('product_type', 'product'), ('program_types', 'program_type'))
    ranking_fields = ('availability_rank', ('product_recent_enrollment_count', 'recent_enrollment_count'),
                      'promoted_in_spanish_index')
    result_fields = (('product_marketing_url', 'marketing_url'), ('product_card_image_url', 'card_image_url'),
                     ('product_uuid', 'uuid'), 'active_run_key', 'active_run_start', 'active_run_type', 'owners',
                     'course_titles')
    # Algolia uses objectID as unique identifier. Can't use straight uuids because a program and a course could
    # have the same one, so we add 'course' or 'program' as a prefix
    object_id_field = (('custom_object_id', 'objectID'), )
    fields = search_fields + facet_fields + ranking_fields + result_fields + object_id_field
    settings = {
        'searchableAttributes': [
            'unordered(title)',  # Algolia best practice: position of the term in plain text fields doesn't matter
            'unordered(primary_description)',
            'unordered(secondary_description)',
            'unordered(tertiary_description)',
            'partner'
        ],
        'attributesForFaceting': ['partner', 'availability', 'subject', 'level', 'language', 'product', 'program_type'],
        'customRanking': ['desc(promoted_in_spanish_index)', 'asc(availability_rank)', 'desc(recent_enrollment_count)']
    }
    index_name = 'spanish_product'
    should_index = 'should_index'

    def get_queryset(self):  # pragma: no cover
        qs1 = [AlgoliaProxyProduct(course, 'es_419') for course in AlgoliaProxyCourse.objects.all()]
        qs2 = [AlgoliaProxyProduct(program, 'es_419') for program in AlgoliaProxyProgram.objects.all()]
        return qs1 + qs2

# Standard algoliasearch_django pattern for populating 2 indices with one model. These are the signatures and structure
# AlgoliaIndex expects, so ignore warnings
# pylint: disable=no-member,super-init-not-called,dangerous-default-value
class ProductMetaIndex(AlgoliaIndex):
    model_index = []

    def __init__(self, model, client, settings):
        self.model_index = [
            ProductIndex(model, client, settings),
            SpanishProductIndex(model, client, settings),
        ]

    def update_obj_index(self, instance):
        for indexer in self.model_index:
            indexer.update_obj_index(instance)

    def delete_obj_index(self, instance):
        for indexer in self.model_index:
            indexer.delete_obj_index(instance)

    def raw_search(self, query='', params={}):
        res = {}
        for indexer in self.model_index:
            res[indexer.name] = indexer.raw_search(query, params)
        return res

    def set_settings(self):
        for indexer in self.model_index:
            indexer.set_settings()

    def clear_index(self):
        for indexer in self.model_index:
            indexer.clear_index()

    def reindex_all(self, batch_size=1000):
        for indexer in self.model_index:
            indexer.reindex_all(batch_size)

register(AlgoliaProxyProduct, index_cls=ProductMetaIndex)
<commit_msg>WS-1022 pin promoted courses/programs in presearch state (#2614)<commit_after>
from algoliasearch_django import AlgoliaIndex, register

from course_discovery.apps.course_metadata.algolia_proxy_models import (
    AlgoliaProxyCourse, AlgoliaProxyProduct, AlgoliaProxyProgram
)

# TODO: make these configurable in Django Admin (WS-1025)
PINNED_COURSE_UUIDS = [
    '0e575a39-da1e-4e33-bb3b-e96cc6ffc58e',
    '911175d0-6724-4276-a058-c7b052773dd1',
    'da1b2400-322b-459b-97b0-0c557f05d017',
    'ff1df27b-3c97-42ee-a9b3-e031ffd41a4f',
    'a00ec61d-e2db-45c8-92c9-4727056c2f4a',
    '605e56d5-08f3-4e90-b4be-2c303def0cd5',
    '327c8e4f-315a-417b-9857-046dfc90c243',
    '0cdd5dc6-a20e-4d34-a346-fcbb9c4249f8',
    'bc4d1642-8b96-44b0-82e8-be8be6e44f94',
    '81cfc304-0eed-4779-9de8-41c79504e456',
    '97f16f83-5e8a-496c-9086-5634c8edccbb',
    'f692cd0b-a77a-4fdf-87db-a309677633e6',
    '15923a19-7f31-4767-a7a0-73da8886f7b8',
    '6e418821-0e4c-4b16-94a3-18979ee49717',
    'c6ad9bb7-cafc-48c8-92e5-5f0900460e66',
    'ec5e106e-18be-4bf3-8721-58950b7da1d4',
    '91f52ef3-fa3f-4934-9d19-8d5a32635cd4',
    '381a0046-5d78-4790-8776-74620d59f48e',
    '8a140470-bc70-4f7f-a9aa-df0284469b0b',
    '459e3763-8724-4f36-9e99-387d55b0dbf5']

PINNED_PROGRAM_UUIDS = [
    '3178ea5b-b7a1-4439-a8b5-aad5df14af34',
    'a3951294-926b-4247-8c3c-51c1e4347a15',
    '3c32e3e0-b6fe-4ee4-bd4f-210c6339e074',
    '9b729425-b524-4344-baaa-107abdee62c6'
]

def get_promoted_courses():
    return [{'objectID': 'course-{uuid}'.format(uuid=uuid), 'position': index} for
            index, uuid in enumerate(PINNED_COURSE_UUIDS)]

def get_promoted_programs():
    return [{'objectID': 'program-{uuid}'.format(uuid=uuid), 'position': index} for
            index, uuid in enumerate(PINNED_PROGRAM_UUIDS)]

class ProductIndex(AlgoliaIndex):
    # promote specified course/program results when query is empty (eg in pre-search state)
    rules = [
        {
            'objectID': 'empty-query-rule-courses',
            'condition': {
                'pattern': '',
                'anchoring': 'is',
                'alternatives': False
            },
            'consequence': {
                'promote': get_promoted_courses(),
                'filterPromotes': True
            },
        },
        {
            'objectID': 'empty-query-rule-programs',
            'condition': {
                'pattern': '',
                'anchoring': 'is',
                'alternatives': False
            },
            'consequence': {
                'promote': get_promoted_programs(),
                'filterPromotes': True
            }
        }
    ]
    search_fields = (('partner_names', 'partner'), ('product_title', 'title'), 'primary_description',
                     'secondary_description', 'tertiary_description')
    facet_fields = (('availability_level', 'availability'), ('subject_names', 'subject'), ('levels', 'level'),
                    ('active_languages', 'language'), ('product_type', 'product'), ('program_types', 'program_type'))
    ranking_fields = ('availability_rank', ('product_recent_enrollment_count', 'recent_enrollment_count'))
    result_fields = (('product_marketing_url', 'marketing_url'), ('product_card_image_url', 'card_image_url'),
                     ('product_uuid', 'uuid'), 'active_run_key', 'active_run_start', 'active_run_type', 'owners',
                     'course_titles')
    # Algolia needs this
    object_id_field = (('custom_object_id', 'objectID'), )
    fields = search_fields + facet_fields + ranking_fields + result_fields + object_id_field
    settings = {
        'searchableAttributes': [
            'unordered(title)',  # AG best practice: position of the search term in plain text fields doesn't matter
            'unordered(primary_description)',
            'unordered(secondary_description)',
            'unordered(tertiary_description)',
            'partner'
        ],
        'attributesForFaceting': ['partner', 'availability', 'subject', 'level', 'language', 'product', 'program_type'],
        'customRanking': ['asc(availability_rank)', 'desc(recent_enrollment_count)']
    }
    index_name = 'product'
    should_index = 'should_index'

    # Bit of a hack: Override get_queryset to return all wrapped versions of all courses and programs rather than an
    # actual queryset to get around the fact that courses and programs have different fields and therefore cannot be
    # combined in a union of querysets. AlgoliaIndex only uses get_queryset as an iterable, so an array works as well.
    def get_queryset(self):  # pragma: no cover
        qs1 = [AlgoliaProxyProduct(course) for course in AlgoliaProxyCourse.objects.all()]
        qs2 = [AlgoliaProxyProduct(program) for program in AlgoliaProxyProgram.objects.all()]
        return qs1 + qs2

    # Rules aren't automatically set in regular reindex_all, so set them explicitly
    def reindex_all(self, batch_size=1000):
        super().reindex_all(batch_size)
        self._AlgoliaIndex__index.replace_all_rules(self.rules)  # pylint: disable=no-member

class SpanishProductIndex(AlgoliaIndex):
    search_fields = (('partner_names', 'partner'), ('product_title', 'title'), 'primary_description',
                     'secondary_description', 'tertiary_description')
    facet_fields = (('availability_level', 'availability'), ('subject_names', 'subject'), ('levels', 'level'),
                    ('active_languages', 'language'), ('product_type', 'product'), ('program_types', 'program_type'))
    ranking_fields = ('availability_rank', ('product_recent_enrollment_count', 'recent_enrollment_count'),
                      'promoted_in_spanish_index')
    result_fields = (('product_marketing_url', 'marketing_url'), ('product_card_image_url', 'card_image_url'),
                     ('product_uuid', 'uuid'), 'active_run_key', 'active_run_start', 'active_run_type', 'owners',
                     'course_titles')
    # Algolia uses objectID as unique identifier. Can't use straight uuids because a program and a course could
    # have the same one, so we add 'course' or 'program' as a prefix
    object_id_field = (('custom_object_id', 'objectID'), )
    fields = search_fields + facet_fields + ranking_fields + result_fields + object_id_field
    settings = {
        'searchableAttributes': [
            'unordered(title)',  # Algolia best practice: position of the term in plain text fields doesn't matter
            'unordered(primary_description)',
            'unordered(secondary_description)',
            'unordered(tertiary_description)',
            'partner'
        ],
        'attributesForFaceting': ['partner', 'availability', 'subject', 'level', 'language', 'product', 'program_type'],
        'customRanking': ['desc(promoted_in_spanish_index)', 'asc(availability_rank)', 'desc(recent_enrollment_count)']
    }
    index_name = 'spanish_product'
    should_index = 'should_index'

    def get_queryset(self):  # pragma: no cover
        qs1 = [AlgoliaProxyProduct(course, 'es_419') for course in AlgoliaProxyCourse.objects.all()]
        qs2 = [AlgoliaProxyProduct(program, 'es_419') for program in AlgoliaProxyProgram.objects.all()]
        return qs1 + qs2

# Standard algoliasearch_django pattern for populating 2 indices with one model. These are the signatures and structure
# AlgoliaIndex expects, so ignore warnings
# pylint: disable=no-member,super-init-not-called,dangerous-default-value
class ProductMetaIndex(AlgoliaIndex):
    model_index = []

    def __init__(self, model, client, settings):
        self.model_index = [
            ProductIndex(model, client, settings),
            SpanishProductIndex(model, client, settings),
        ]

    def update_obj_index(self, instance):
        for indexer in self.model_index:
            indexer.update_obj_index(instance)

    def delete_obj_index(self, instance):
        for indexer in self.model_index:
            indexer.delete_obj_index(instance)

    def raw_search(self, query='', params={}):
        res = {}
        for indexer in self.model_index:
            res[indexer.name] = indexer.raw_search(query, params)
        return res

    def set_settings(self):
        for indexer in self.model_index:
            indexer.set_settings()

    def clear_index(self):
        for indexer in self.model_index:
            indexer.clear_index()

    def reindex_all(self, batch_size=1000):
        for indexer in self.model_index:
            indexer.reindex_all(batch_size)

register(AlgoliaProxyProduct, index_cls=ProductMetaIndex)
<|endoftext|>


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

from django.conf import settings
from django.conf.urls import url
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.shortcuts import get_object_or_404

from tastypie import http, fields
from tastypie.constants import ALL, ALL_WITH_RELATIONS
from tastypie.exceptions import ImmediateHttpResponse
from tastypie.resources import ModelResource
from tastypie.utils import trailing_slash
from tastypie.validation import Validation
from schematics.models import Model as SchemaModel
from schematics.types import IntType
from social.backends.utils import get_backend
from social.apps.django_app.utils import load_strategy

from .fields import GeoPointField
from .authentication import PostFreeSessionAuthentication
from .authorization import CreateFreeDjangoAuthorization
from ..models import Event, EventUpdate
from core.api.decorators import api_method, body_params
from users.api.resources import UserResource

logger = logging.getLogger(__name__)

class MultipartResource(object):
    """
    This class allows resources to receive files using multipart content type
    """
    def deserialize(self, request, data, format=None):
        if not format:
            format = request.META.get('CONTENT_TYPE', 'application/json')

        if format == 'application/x-www-form-urlencoded':
            return request.POST

        if format.startswith('multipart'):
            data = request.POST.copy()
            data.update(request.FILES)
            return data
        return super(MultipartResource, self).deserialize(request, data, format)

class EventResource(ModelResource):
    class Meta:
        queryset = Event.objects.all()
        resource_name = 'events'
        authentication = PostFreeSessionAuthentication()
        authorization = CreateFreeDjangoAuthorization()
        list_allowed_methods = ['post', 'get']
        fields = ['id', 'user', 'type', 'status']
        filtering = {
            'id': ALL,
            'status': ALL,
        }
        detail_allowed_methods = []
        always_return_data = True

    user = fields.ForeignKey(UserResource, 'user', full=True, readonly=True)
    type = fields.CharField('get_type_display', readonly=True)
    latest_location = GeoPointField('latest_location', null=True, readonly=True)
    latest_update = fields.ForeignKey('events.api.resources.EventUpdateResource',
                                      'latest_update',
                                      full=True, null=True, readonly=True)

    def prepend_urls(self):
        return [
            url(r'^(?P<resource_name>%s)/(?P<pk>\d+)/support%s$' %
                (self._meta.resource_name, trailing_slash()),
                self.wrap_view('support'), name='api_events_support'),
        ]

    @api_method
    def support(self):
        """
        ***
        TODO: replace ``user_id`` with ``request.user``.
        ***

        Marks user as "supporter" for a given event.
        Accepts args as json object.

        * For **POST** method, adds user with given ``user_id`` param to list
          of event's supporters.

        Raises 400 if ``used_id`` param is not a number.
        Raises 404 if user with given ``user_id`` or given event pk is not found.
        """
        class PostParams(SchemaModel):
            user_id = IntType(required=True)

        @body_params(PostParams)
        def post(self, request, pk=None, params=None, **kwargs):
            try:
                user = User.objects.get(id=params.user_id)
            except User.DoesNotExist:
                return http.HttpBadRequest()
            else:
                target_event = get_object_or_404(Event, id=pk)
                target_event.support_by_user(user)

        return post

    def hydrate(self, bundle):
        bundle.obj.user = bundle.request.user;
        return bundle

    def dehydrate(self, bundle):
        if bundle.request.META['REQUEST_METHOD'] == 'POST':
            bundle.data['key'] = bundle.obj.key

        return bundle

class EventUpdateValidation(Validation):
    def is_valid(self, bundle, request=None):
        if not bundle.data:
            return {'__all__': 'Please add key and other arguments'}

        errors = {}

        key = bundle.data.get('key')
        if not key:
            errors['key'] = 'Key is required'

        if bundle.data.keys() == ['key']:
            errors['__all__'] = 'Additional arguments required'

        return errors

class EventUpdateResource(MultipartResource, ModelResource):
    class Meta:
        queryset = EventUpdate.objects.order_by('-timestamp')
        resource_name = 'eventupdates'
        list_allowed_methods = ['post', 'get']
        detail_allowed_methods = []
        filtering = {'event': ALL_WITH_RELATIONS}
        validation = EventUpdateValidation()
        authentication = PostFreeSessionAuthentication()
        authorization = CreateFreeDjangoAuthorization()

    location = GeoPointField('location', null=True)
    event = fields.ForeignKey(EventResource, 'event', readonly=True)

    def hydrate(self, bundle):
        key = bundle.data.get('key')
        if key:
            event = get_object_or_404(Event, key=key)
            bundle.obj.event = event

        return bundle
<commit_msg>Fixed merge<commit_after># -*- coding: utf-8 -*-
import logging

from django.conf import settings
from django.conf.urls import url
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.shortcuts import get_object_or_404

from tastypie import http, fields
from tastypie.constants import ALL, ALL_WITH_RELATIONS
from tastypie.exceptions import ImmediateHttpResponse
from tastypie.resources import ModelResource
from tastypie.utils import trailing_slash
from tastypie.validation import Validation
from schematics.models import Model as SchemaModel
from schematics.types import IntType

from .fields import GeoPointField
from .authentication import PostFreeSessionAuthentication
from .authorization import CreateFreeDjangoAuthorization
from ..models import Event, EventUpdate
from core.api.decorators import api_method, body_params
from users.api.resources import UserResource

logger = logging.getLogger(__name__)

class MultipartResource(object):
    """
    This class allows resources to receive files using multipart content type
    """
    def deserialize(self, request, data, format=None):
        if not format:
            format = request.META.get('CONTENT_TYPE', 'application/json')

        if format == 'application/x-www-form-urlencoded':
            return request.POST

        if format.startswith('multipart'):
            data = request.POST.copy()
            data.update(request.FILES)
            return data
        return super(MultipartResource, self).deserialize(request, data, format)

class EventResource(ModelResource):
    class Meta:
        queryset = Event.objects.all()
        resource_name = 'events'
        authentication = PostFreeSessionAuthentication()
        authorization = CreateFreeDjangoAuthorization()
        list_allowed_methods = ['post', 'get']
        fields = ['id', 'user', 'type', 'status']
        filtering = {
            'id': ALL,
            'status': ALL,
        }
        detail_allowed_methods = []
        always_return_data = True

    user = fields.ForeignKey(UserResource, 'user', full=True, readonly=True)
    type = fields.CharField('get_type_display', readonly=True)
    latest_location = GeoPointField('latest_location', null=True, readonly=True)
    latest_update = fields.ForeignKey('events.api.resources.EventUpdateResource',
                                      'latest_update',
                                      full=True, null=True, readonly=True)

    def prepend_urls(self):
        return [
            url(r'^(?P<resource_name>%s)/(?P<pk>\d+)/support%s$' %
                (self._meta.resource_name, trailing_slash()),
                self.wrap_view('support'), name='api_events_support'),
        ]

    @api_method
    def support(self):
        """
        ***
        TODO: replace ``user_id`` with ``request.user``.
        ***

        Marks user as "supporter" for a given event.
        Accepts args as json object.

        * For **POST** method, adds user with given ``user_id`` param to list
          of event's supporters.

        Raises 400 if ``used_id`` param is not a number.
        Raises 404 if user with given ``user_id`` or given event pk is not found.
        """
        class PostParams(SchemaModel):
            user_id = IntType(required=True)

        @body_params(PostParams)
        def post(self, request, pk=None, params=None, **kwargs):
            try:
                user = User.objects.get(id=params.user_id)
            except User.DoesNotExist:
                return http.HttpBadRequest()
            else:
                target_event = get_object_or_404(Event, id=pk)
                target_event.support_by_user(user)

        return post

    def hydrate(self, bundle):
        bundle.obj.user = bundle.request.user;
        return bundle

    def dehydrate(self, bundle):
        if bundle.request.META['REQUEST_METHOD'] == 'POST':
            bundle.data['key'] = bundle.obj.key

        return bundle

class EventUpdateValidation(Validation):
    def is_valid(self, bundle, request=None):
        if not bundle.data:
            return {'__all__': 'Please add key and other arguments'}

        errors = {}

        key = bundle.data.get('key')
        if not key:
            errors['key'] = 'Key is required'

        if bundle.data.keys() == ['key']:
            errors['__all__'] = 'Additional arguments required'

        return errors

class EventUpdateResource(MultipartResource, ModelResource):
    class Meta:
        queryset = EventUpdate.objects.order_by('-timestamp')
        resource_name = 'eventupdates'
        list_allowed_methods = ['post', 'get']
        detail_allowed_methods = []
        filtering = {'event': ALL_WITH_RELATIONS}
        validation = EventUpdateValidation()
        authentication = PostFreeSessionAuthentication()
        authorization = CreateFreeDjangoAuthorization()

    location = GeoPointField('location', null=True)
    event = fields.ForeignKey(EventResource, 'event', readonly=True)

    def hydrate(self, bundle):
        key = bundle.data.get('key')
        if key:
            event = get_object_or_404(Event, key=key)
            bundle.obj.event = event

        return bundle
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    Author: Yannick Vaucher
#    Copyright 2013 Camptocamp SA
#
#    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/>.
#
##############################################################################
{'name': 'PostLogistics labels - logo per Shop',
 'version': '1.0',
 'author': 'Camptocamp',
 'maintainer': 'Camptocamp',
 'category': 'version',
 'complexity': 'normal',
 'depends': ['delivery_carrier_label_postlogistics'],
 'description': """
PostLogistics labels - logo per Shop
===================================

Add an option to define a logo per shop if no shop logo is defined

Contributors
------------

* Yannick Vaucher <yannick.vaucher@camptocamp.com>

""",
 'website': 'http://www.camptocamp.com/',
 'data': ['sale_view.xml'],
 'test': [],
 'installable': True,
 'auto_install': False,
 'application': True,
 }
<commit_msg>[IMP] __openerp__ description<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    Author: Yannick Vaucher
#    Copyright 2013 Camptocamp SA
#
#    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/>.
#
##############################################################################
{'name': 'PostLogistics labels - logo per Shop',
 'version': '1.0',
 'author': 'Camptocamp',
 'maintainer': 'Camptocamp',
 'category': 'version',
 'complexity': 'normal',
 'depends': ['delivery_carrier_label_postlogistics'],
 'description': """
PostLogistics labels - logo per Shop
===================================

Add an option to define a logo per shop.
If no shop logo is defined uses company logo.

Contributors
------------

* Yannick Vaucher <yannick.vaucher@camptocamp.com>

""",
 'website': 'http://www.camptocamp.com/',
 'data': ['sale_view.xml'],
 'test': [],
 'installable': True,
 'auto_install': False,
 'application': True,
 }
<|endoftext|>


<commit_before>"""
UserES
------

Here's an example adapted from the case list report - it gets a list of the ids
of all unknown users, web users, and demo users on a domain.

.. code-block:: python

    from corehq.apps.es import users as user_es

    user_filters = [
        user_es.unknown_users(),
        user_es.web_users(),
        user_es.demo_users(),
    ]

    query = (user_es.UserES()
             .domain(self.domain)
             .OR(*user_filters)
             .show_inactive())

    owner_ids = query.get_ids()
"""
from copy import deepcopy

from . import filters, queries
from .es_query import HQESQuery

class UserES(HQESQuery):
    index = 'users'
    default_filters = {
        'not_deleted': filters.term("base_doc", "couchuser"),
        'active': filters.term("is_active", True),
    }

    @property
    def builtin_filters(self):
        return [
            domain,
            created,
            mobile_users,
            web_users,
            user_ids,
            primary_location,
            location,
            last_logged_in,
            analytics_enabled,
            is_practice_user,
            role_id,
            is_active,
            username,
            metadata,
        ] + super(UserES, self).builtin_filters

    def show_inactive(self):
        """Include inactive users, which would normally be filtered out."""
        return self.remove_default_filter('active')

    def show_only_inactive(self):
        query = self.remove_default_filter('active')
        return query.is_active(False)

def domain(domain, allow_mirroring=False):
    domains = [domain]
    if allow_mirroring:
        from corehq.apps.users.models import DomainPermissionsMirror
        source_domain = DomainPermissionsMirror.source_domain(domain)
        if source_domain:
            domains.append(source_domain)
    return filters.OR(
        filters.term("domain.exact", domains),
        filters.term("domain_memberships.domain.exact", domains)
    )

def analytics_enabled(enabled=True):
    if enabled:
        return filters.OR(
            filters.term("analytics_enabled", True),
            filters.missing("analytics_enabled")
        )
    else:
        return filters.term("analytics_enabled", False)

def username(username):
    return filters.term("username.exact", username)

def web_users():
    return filters.doc_type("WebUser")

def mobile_users():
    return filters.doc_type("CommCareUser")

def unknown_users():
    """
    Return only UnknownUsers.  Unknown users are mock users created from xform
    submissions with unknown user ids.
    """
    return filters.doc_type("UnknownUser")

def admin_users():
    """
    Return only AdminUsers.  Admin users are mock users created from xform
    submissions with unknown user ids whose username is "admin".
    """
    return filters.doc_type("AdminUser")

def demo_users():
    """Matches users whose username is demo_user"""
    return username("demo_user")

def created(gt=None, gte=None, lt=None, lte=None):
    return filters.date_range('created_on', gt, gte, lt, lte)

def last_logged_in(gt=None, gte=None, lt=None, lte=None):
    return filters.date_range('last_login', gt, gte, lt, lte)

def user_ids(user_ids):
    return filters.term("_id", list(user_ids))

def primary_location(location_id):
    # by primary location
    return filters.OR(
        filters.AND(mobile_users(), filters.term('location_id', location_id)),
        filters.AND(
            web_users(),
            filters.term('domain_memberships.location_id', location_id)
        ),
    )

def location(location_id):
    # by any assigned-location primary or not
    return filters.OR(
        filters.AND(mobile_users(), filters.term('assigned_location_ids', location_id)),
        # todo; this actually doesn't get applied since the below field is not indexed
        filters.AND(
            web_users(),
            filters.term('domain_memberships.assigned_location_ids', location_id)
        ),
    )

def is_practice_user(practice_mode=True):
    return filters.term('is_demo_user', practice_mode)

def role_id(role_id):
    return filters.OR(
        filters.term("domain_membership.role_id", role_id),     # mobile users
        filters.term("domain_memberships.role_id", role_id)     # web users
    )

def is_active(active=True):
    return filters.term("is_active", active)

def metadata(key, value):
    return queries.nested(
        'user_data_es',
        filters.AND(
            filters.term(field='user_data_es.key', value=key),
            queries.match(field='user_data_es.value', search_string=value, fuzziness=0),
        )
    )
<commit_msg>Make a note about the various field names<commit_after>"""
UserES
------

Here's an example adapted from the case list report - it gets a list of the ids
of all unknown users, web users, and demo users on a domain.

.. code-block:: python

    from corehq.apps.es import users as user_es

    user_filters = [
        user_es.unknown_users(),
        user_es.web_users(),
        user_es.demo_users(),
    ]

    query = (user_es.UserES()
             .domain(self.domain)
             .OR(*user_filters)
             .show_inactive())

    owner_ids = query.get_ids()
"""
from copy import deepcopy

from . import filters, queries
from .es_query import HQESQuery

class UserES(HQESQuery):
    index = 'users'
    default_filters = {
        'not_deleted': filters.term("base_doc", "couchuser"),
        'active': filters.term("is_active", True),
    }

    @property
    def builtin_filters(self):
        return [
            domain,
            created,
            mobile_users,
            web_users,
            user_ids,
            primary_location,
            location,
            last_logged_in,
            analytics_enabled,
            is_practice_user,
            role_id,
            is_active,
            username,
            metadata,
        ] + super(UserES, self).builtin_filters

    def show_inactive(self):
        """Include inactive users, which would normally be filtered out."""
        return self.remove_default_filter('active')

    def show_only_inactive(self):
        query = self.remove_default_filter('active')
        return query.is_active(False)

def domain(domain, allow_mirroring=False):
    domains = [domain]
    if allow_mirroring:
        from corehq.apps.users.models import DomainPermissionsMirror
        source_domain = DomainPermissionsMirror.source_domain(domain)
        if source_domain:
            domains.append(source_domain)
    return filters.OR(
        filters.term("domain.exact", domains),
        filters.term("domain_memberships.domain.exact", domains)
    )

def analytics_enabled(enabled=True):
    if enabled:
        return filters.OR(
            filters.term("analytics_enabled", True),
            filters.missing("analytics_enabled")
        )
    else:
        return filters.term("analytics_enabled", False)

def username(username):
    return filters.term("username.exact", username)

def web_users():
    return filters.doc_type("WebUser")

def mobile_users():
    return filters.doc_type("CommCareUser")

def unknown_users():
    """
    Return only UnknownUsers.  Unknown users are mock users created from xform
    submissions with unknown user ids.
    """
    return filters.doc_type("UnknownUser")

def admin_users():
    """
    Return only AdminUsers.  Admin users are mock users created from xform
    submissions with unknown user ids whose username is "admin".
    """
    return filters.doc_type("AdminUser")

def demo_users():
    """Matches users whose username is demo_user"""
    return username("demo_user")

def created(gt=None, gte=None, lt=None, lte=None):
    return filters.date_range('created_on', gt, gte, lt, lte)

def last_logged_in(gt=None, gte=None, lt=None, lte=None):
    return filters.date_range('last_login', gt, gte, lt, lte)

def user_ids(user_ids):
    return filters.term("_id", list(user_ids))

def primary_location(location_id):
    # by primary location
    return filters.OR(
        filters.AND(mobile_users(), filters.term('location_id', location_id)),
        filters.AND(
            web_users(),
            filters.term('domain_memberships.location_id', location_id)
        ),
    )

def location(location_id):
    # by any assigned-location primary or not
    return filters.OR(
        filters.AND(mobile_users(), filters.term('assigned_location_ids', location_id)),
        # todo; this actually doesn't get applied since the below field is not indexed
        filters.AND(
            web_users(),
            filters.term('domain_memberships.assigned_location_ids', location_id)
        ),
    )

def is_practice_user(practice_mode=True):
    return filters.term('is_demo_user', practice_mode)

def role_id(role_id):
    return filters.OR(
        filters.term("domain_membership.role_id", role_id),     # mobile users
        filters.term("domain_memberships.role_id", role_id)     # web users
    )

def is_active(active=True):
    return filters.term("is_active", active)

def metadata(key, value):
    # Note that this dict is stored in ES under the `user_data` field, and
    # transformed into a queryable format (in ES) as `user_data_es`, but it's
    # referenced in python as `metadata`
    return queries.nested(
        'user_data_es',
        filters.AND(
            filters.term(field='user_data_es.key', value=key),
            queries.match(field='user_data_es.value', search_string=value, fuzziness=0),
        )
    )
<|endoftext|>