<commit_before>import sys
import subprocess
import time
import re

class TrackValidation:
    '''
    Class for deciding whether a track summary from a run should be
    considered valid based on the overheads and response times recorded
    '''
    def __init__(self, trackname):
        self.track_name = trackname
        self.pct_overhead_ops = 0.0
        self.pct_overhead_ops_acceptable = False
        self.pct_ops_failed = 0.0
        self.pct_failed_ops_acceptable = False
        self.op_response_time_targets_met = True

    def is_acceptable(self):
        return self.pct_overhead_ops_acceptable and \
            self.pct_failed_ops_acceptable and \
            self.op_response_time_targets_met

class TrackSummary:
    '''
    Class for storing the summary results of a load track
    '''
    def __init__(self, trackname):
        self.name = trackname
        self.offered_load_ops_per_sec = 0
        self.effective_load_ops_per_sec = 0
        self.littles_estimate_ops_per_sec = 0
        self.effective_load_reqs_per_sec = 0
        self.operations_successful = 0
        self.operations_failed = 0
        self.average_op_response_time_sec = 0
        self.average_users = 0
        #self.op_response_time_targets_met = True
        self.op_response_times = {}
        # Specifiy validation thresholds
        self.pct_overhead_ops_threshold=5.0
        self.pct_failed_ops_threshold=5.0
        self.op_response_time_thresholds = {}

    def validate( self ):
        result = TrackValidation(self.name)
        # check overheads

        if self.littles_estimate_ops_per_sec > 0:
            result.pct_overhead_ops = \
                ((self.littles_estimate_ops_per_sec - \
                      self.effective_load_ops_per_sec)/\
                     self.littles_estimate_ops_per_sec)*100.0

            if result.pct_overhead_ops <= self.pct_overhead_ops_threshold:
                result.pct_overhead_ops_acceptable = True
        else:
            result.pct_overhead_ops_acceptable = False

        total_ops = self.operations_successful + self.operations_failed
        result.pct_ops_failed = \
            (float(self.operations_failed)/float(total_ops))*100.0

        if result.pct_ops_failed <= self.pct_failed_ops_threshold:
            result.pct_failed_ops_acceptable = True

        # For each of the op_response_time thresholds
        # see if they've been met
        for k,v in self.op_response_time_thresholds.items():
            if self.op_response_times.has_key( k ):
                observed = self.op_response_times[k]
                if observed[0] > v[0] or observed[1] > v[1]:
                    result.op_response_time_targets_met = False

        return result

    def __repr__(self):
        '''
        Craft our own string representation
        '''
        # Validate ourselves first
        # Construct the string with our results
        # callers can print this out, write it to a file, etc.
        validation = self.validate()

        return RainOutputParser.RESULTS_DATA.format(\
            self.name, \
            self.effective_load_ops_per_sec, \
            self.littles_estimate_ops_per_sec,\
            self.effective_load_reqs_per_sec, \
            validation.pct_overhead_ops, \
            self.average_op_response_time_sec, \
            self.average_users, \
            self.operations_successful, \
            self.operations_failed, \
            validation.pct_ops_failed, \
            str(validation.is_acceptable()) )

class RainOutputParser:
    '''
    Class for parsing the output from Rain. Returns a list of track summaries
    '''
    RESULTS_HEADER = "{0:<20} {1:<10s} {2:<10s} {3:<10s} {4:<10s} {5:<10s} "\
                "{6:<10s} {7:<10s} {8:<10s} {9:<10s} {10:<5s}".format(\
                "track",\
                "eff-ops/s",\
                "ltl-ops/s",\
                "eff-reqs/s",\
                "%ovh-ops",\
                "avg-resp(s)",\
                "avg-users",\
                "succeeded",\
                "failed",\
                "%failed",\
                "passed" )
    RESULTS_DATA = "{0:<20} {1:10.4f} {2:10.4f} {3:10.4f} {4:10.4f} {5:10.4f}"\
                   "{6:10.4f} {7:10} {8:10} {9:10.4f} {10:<5s}"

    @staticmethod
    def parse_output( output ):
        '''
        Parse the output for each track and return a list with summary results
        for each track
        '''
        #print output
        # Find all the track names
        track_results = []
        track_pattern = re.compile( '\[TRACK: (.*)\] starting load scheduler' )
        tracks = track_pattern.findall( output )

        # for each track go get some numbers from the final results section
        for track in tracks:
            #print track
            # sub-pattern of the end of a result line from rain
            # <metric><space*>:<space+><decimal value>
            number_pattern = '([-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?)'
            result_line_tail_pattern = \
                '\s*:\s+([-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?)'
            track_final_results_pattern = \
              re.compile( '\[SCOREBOARD TRACK: ' + track + '\] Final results' )
            track_offered_load_ops_pattern = \
                re.compile( '\[SCOREBOARD TRACK: ' + track + '\] ' \
                       'Offered load \(ops/sec\)' + result_line_tail_pattern )
            track_effective_load_ops_pattern = \
                re.compile( '\[SCOREBOARD TRACK: ' + track + '\] ' \
                      'Effective load \(ops/sec\)' + result_line_tail_pattern )
            track_littles_estimate_ops_pattern = \
              re.compile( '\[SCOREBOARD TRACK: ' + track + '\] ' \
              'Little\'s Law Estimate \(ops/sec\)' + result_line_tail_pattern )
            track_effective_load_reqs_pattern = \
                re.compile( '\[SCOREBOARD TRACK: ' + track + '\] ' \
                'Effective load \(requests/sec\)' + result_line_tail_pattern )
            track_ops_successful_pattern = \
               re.compile( '\[SCOREBOARD TRACK: ' + track + '\] ' \
               'Operations successfully completed' + result_line_tail_pattern )
            track_ops_failed_pattern = \
               re.compile( '\[SCOREBOARD TRACK: ' + track + '\] ' \
                           'Operations failed' + result_line_tail_pattern )
            track_avg_op_response_time_pattern = \
             re.compile( '\[SCOREBOARD TRACK: ' + track + '\] ' \
                         'Average operation response time \(s\)' + \
                             result_line_tail_pattern )
            track_avg_users_pattern = \
                re.compile( '\[SCOREBOARD TRACK: ' + track + '\] ' \
                      'Average number of users' + result_line_tail_pattern )

            # Patterns for operations - doesn't group like we'd like
            # but matches the right lines
            track_operation_pattern = \
                re.compile( '\[SCOREBOARD TRACK: ' + track + '\]' \
                       '\|(.+)\|'\
                       '\s*(' + number_pattern + ')%\s*\|'\
                       '\s*(' + number_pattern + ')\s*\|'\
                       '\s*(' + number_pattern + ')\s*\|'\
                       '\s*(' + number_pattern + ')\s*\|'\
                       '\s*(' + number_pattern + ')\s*\|'\
                       '\s*(' + number_pattern + ')\s*\|'\
                       '\s*(' + number_pattern + ')\s*\|'\
                       '\s*(' + number_pattern + ')\s*\|')

            # Create a new track summary instance to fill in
            summary = TrackSummary(track)
            # Find the "Final results" marker for this track and then
            # search for individual metrics
            match = track_final_results_pattern.search( output )
            if match:
                # search the substring from the final results marker
                # for more specific stuff after this point
                final_results_section_start = match.start()
                summary.offered_load_ops_per_sec = \
                    float( track_offered_load_ops_pattern.search\
                             ( output, final_results_section_start ).group(1) )
                summary.effective_load_ops_per_sec = \
                    float( track_effective_load_ops_pattern.search\
                             ( output, final_results_section_start ).group(1) )
                summary.littles_estimate_ops_per_sec = \
                    float( track_littles_estimate_ops_pattern.search\
                             ( output, final_results_section_start ).group(1) )
                summary.effective_load_reqs_per_sec = \
                    float( track_effective_load_reqs_pattern.search\
                             ( output, final_results_section_start ).group(1) )
                summary.operations_successful = \
                    long( track_ops_successful_pattern.search\
                             ( output, final_results_section_start ).group(1) )
                summary.operations_failed = \
                    long( track_ops_failed_pattern.search\
                             ( output, final_results_section_start ).group(1) )
                summary.average_op_response_time_sec = \
                    float( track_avg_op_response_time_pattern.search\
                             ( output, final_results_section_start ).group(1) )
                summary.average_users = \
                    float( track_avg_users_pattern.search\
                             ( output, final_results_section_start ).group(1) )

                # find all the operations and print out the 90th and 99th
                # percentiles
                for opMatch in track_operation_pattern.\
                    finditer( output, final_results_section_start ):

                    #print opMatch
                    #print opMatch.group(0)
                    # Split group(0) on |
                    opCounters = opMatch.group(0).split( "|" )
                    #for s in opCounters:
                    #    print s
                    #print opCounters[1].strip(), opCounters[8], opCounters[9]
                    # Store the op name with a tuple (90th pct,99th pct)
                    summary.op_response_times[opCounters[1].strip()]=\
                        (float(opCounters[8].strip()), \
                             float(opCounters[9].strip()))
                #else:
                #   print "no operation match"

                # save the summary to the list we have so far
                #print summary.name, summary.op_response_times
                track_results.append(summary)

        # return the list of track results we found
        return track_results

    @staticmethod
    def print_results( results, output_stream=sys.stdout ):
        output_stream.write( RainOutputParser.RESULTS_HEADER + '\n' )
        for result in results:
            output_stream.write( str(result) + '\n' )
        # Flush the output stream
        output_stream.flush()

class RunManager():
    """
    A class for launching runs and validating results.
    """
    @staticmethod
    def run_rain( config_file="config/rain.config.ac.json", \
                  classpath=".:rain.jar:workloads/httptest.jar", \
                  min_heapsize="-Xms256m", \
                  max_heapsize="-Xmx1g", \
                  gc_policy="-XX:+DisableExplicitGC" ):
        """
        Launch process for Rain, get pid and then start querying
        sched stats
        """
        args = ["java", min_heapsize, max_heapsize, gc_policy, \
            "-cp", classpath, "radlab.rain.Benchmark", config_file  ]

        rain_process = None
        rain_process = subprocess.Popen(args, bufsize=-1, \
                                stdin=subprocess.PIPE, stdout=subprocess.PIPE)
        rain_pid = rain_process.pid
        print( "[Run manager] rain pid: %d" % rain_pid )

        # Sit and wait until Rain exits then parse the output
        # Return the raw output, clients can parse it themselves
        # or use the RainOutputParser to make sense
        # of it
        #output = rain_process.stdout.read()
        output, err = rain_process.communicate()
        return output

'''
Example command line
java -Xms256m -Xmx1g -XX:+DisableExplicitGC -cp .:rain.jar:workloads/httptest.jar radlab.rain.Benchmark config/rain.config.ac.json
'''

def run2():
    try:
        #results_file = open( "./rain.out", 'r' )
        results_file = open( "./rain.predictable.out", 'r' )
        results = results_file.read()
        track_results = RainOutputParser.parse_output( results )
        for result in track_results:
            # Set some 90th and 99th pctile thresholds
            result.op_response_time_thresholds['PingHome']=(0.001,0.005)

        RainOutputParser.print_results( track_results )
    #except:
    #    print "something broke"
    finally:
        if not results_file.closed:
            results_file.close()

def run3():

    config_file = "config/rain.config.ac.json"
    classpath = ".:rain.jar:workloads/httptest.jar"
    output = RunManager.run_rain(config_file, classpath)
    track_results = RainOutputParser.parse_output( output )
    RainOutputParser.print_results( track_results, sys.stdout )
    #return track_results

if __name__=='__main__':
      run2()
<commit_msg>Updated the run_manager to show validation notes in run results so we can see right away why a run failed.<commit_after>import sys
import subprocess
import time
import re

class TrackValidation:
    '''
    Class for deciding whether a track summary from a run should be
    considered valid based on the overheads and response times recorded
    '''
    def __init__(self, trackname):
        self.track_name = trackname
        self.pct_overhead_ops = 0.0
        self.pct_overhead_ops_acceptable = False
        self.pct_ops_failed = 0.0
        self.pct_failed_ops_acceptable = False
        self.op_response_time_targets_met = True

    def is_acceptable(self):
        return self.pct_overhead_ops_acceptable and \
            self.pct_failed_ops_acceptable and \
            self.op_response_time_targets_met

class TrackSummary:
    '''
    Class for storing the summary results of a load track
    '''
    def __init__(self, trackname):
        self.name = trackname
        self.offered_load_ops_per_sec = 0
        self.effective_load_ops_per_sec = 0
        self.littles_estimate_ops_per_sec = 0
        self.effective_load_reqs_per_sec = 0
        self.operations_successful = 0
        self.operations_failed = 0
        self.average_op_response_time_sec = 0
        self.average_users = 0
        #self.op_response_time_targets_met = True
        self.op_response_times = {}
        # Specifiy validation thresholds
        self.pct_overhead_ops_threshold=5.0
        self.pct_failed_ops_threshold=5.0
        self.op_response_time_thresholds = {}
        self.validation_note = "n/a"

    def validate( self ):
        result = TrackValidation(self.name)
        # check overheads

        if self.littles_estimate_ops_per_sec > 0:
            result.pct_overhead_ops = \
                ((self.littles_estimate_ops_per_sec - \
                      self.effective_load_ops_per_sec)/\
                     self.littles_estimate_ops_per_sec)*100.0

            if result.pct_overhead_ops <= self.pct_overhead_ops_threshold:
                result.pct_overhead_ops_acceptable = True
        else:
            result.pct_overhead_ops_acceptable = False
            self.validation_note = "little's law overhead > {0}%"\
                .format(self.pct_overhead_ops_threshold)

        total_ops = self.operations_successful + self.operations_failed
        result.pct_ops_failed = \
            (float(self.operations_failed)/float(total_ops))*100.0

        if result.pct_ops_failed <= self.pct_failed_ops_threshold:
            result.pct_failed_ops_acceptable = True
        else:
            self.validation_note = "pct ops failed > {0}%"\
                .format(self.pct_failed_ops_threshold)

        # For each of the op_response_time thresholds
        # see if they've been met
        for k,v in self.op_response_time_thresholds.items():
            if self.op_response_times.has_key( k ):
                observed = self.op_response_times[k]
                if observed[0] > v[0] or observed[1] > v[1]:
                    result.op_response_time_targets_met = False
                    self.validation_note = "response time target(s) not met"
        return result

    def __repr__(self):
        '''
        Craft our own string representation
        '''
        # Validate ourselves first
        # Construct the string with our results
        # callers can print this out, write it to a file, etc.
        validation = self.validate()

        return RainOutputParser.RESULTS_DATA.format(\
            self.name, \
            self.effective_load_ops_per_sec, \
            self.littles_estimate_ops_per_sec,\
            self.effective_load_reqs_per_sec, \
            validation.pct_overhead_ops, \
            self.average_op_response_time_sec, \
            self.average_users, \
            self.operations_successful, \
            self.operations_failed, \
            validation.pct_ops_failed, \
            str(validation.is_acceptable()),\
            self.validation_note )

class RainOutputParser:
    '''
    Class for parsing the output from Rain. Returns a list of track summaries
    '''
    RESULTS_HEADER = "{0:<20} {1:<10s} {2:<10s} {3:<10s} {4:<10s} {5:<10s} "\
                "{6:<10s} {7:<10s} {8:<10s} {9:<10s} {10:<5s} {11}".format(\
                "track",\
                "eff-ops/s",\
                "ltl-ops/s",\
                "eff-reqs/s",\
                "%ovh-ops",\
                "avg-resp(s)",\
                "avg-users",\
                "succeeded",\
                "failed",\
                "%failed",\
                "passed",\
                "note")
    RESULTS_DATA = "{0:<20} {1:10.4f} {2:10.4f} {3:10.4f} {4:10.4f} {5:10.4f}"\
                   "{6:10.4f} {7:10} {8:10} {9:10.4f} {10:<5s} ({11})"

    @staticmethod
    def parse_output( output ):
        '''
        Parse the output for each track and return a list with summary results
        for each track
        '''
        #print output
        # Find all the track names
        track_results = []
        track_pattern = re.compile( '\[TRACK: (.*)\] starting load scheduler' )
        tracks = track_pattern.findall( output )

        # for each track go get some numbers from the final results section
        for track in tracks:
            #print track
            # sub-pattern of the end of a result line from rain
            # <metric><space*>:<space+><decimal value>
            number_pattern = '([-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?)'
            result_line_tail_pattern = \
                '\s*:\s+([-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?)'
            track_final_results_pattern = \
              re.compile( '\[SCOREBOARD TRACK: ' + track + '\] Final results' )
            track_offered_load_ops_pattern = \
                re.compile( '\[SCOREBOARD TRACK: ' + track + '\] ' \
                       'Offered load \(ops/sec\)' + result_line_tail_pattern )
            track_effective_load_ops_pattern = \
                re.compile( '\[SCOREBOARD TRACK: ' + track + '\] ' \
                      'Effective load \(ops/sec\)' + result_line_tail_pattern )
            track_littles_estimate_ops_pattern = \
              re.compile( '\[SCOREBOARD TRACK: ' + track + '\] ' \
              'Little\'s Law Estimate \(ops/sec\)' + result_line_tail_pattern )
            track_effective_load_reqs_pattern = \
                re.compile( '\[SCOREBOARD TRACK: ' + track + '\] ' \
                'Effective load \(requests/sec\)' + result_line_tail_pattern )
            track_ops_successful_pattern = \
               re.compile( '\[SCOREBOARD TRACK: ' + track + '\] ' \
               'Operations successfully completed' + result_line_tail_pattern )
            track_ops_failed_pattern = \
               re.compile( '\[SCOREBOARD TRACK: ' + track + '\] ' \
                           'Operations failed' + result_line_tail_pattern )
            track_avg_op_response_time_pattern = \
             re.compile( '\[SCOREBOARD TRACK: ' + track + '\] ' \
                         'Average operation response time \(s\)' + \
                             result_line_tail_pattern )
            track_avg_users_pattern = \
                re.compile( '\[SCOREBOARD TRACK: ' + track + '\] ' \
                      'Average number of users' + result_line_tail_pattern )

            # Patterns for operations - doesn't group like we'd like
            # but matches the right lines
            track_operation_pattern = \
                re.compile( '\[SCOREBOARD TRACK: ' + track + '\]' \
                       '\|(.+)\|'\
                       '\s*(' + number_pattern + ')%\s*\|'\
                       '\s*(' + number_pattern + ')\s*\|'\
                       '\s*(' + number_pattern + ')\s*\|'\
                       '\s*(' + number_pattern + ')\s*\|'\
                       '\s*(' + number_pattern + ')\s*\|'\
                       '\s*(' + number_pattern + ')\s*\|'\
                       '\s*(' + number_pattern + ')\s*\|'\
                       '\s*(' + number_pattern + ')\s*\|')

            # Create a new track summary instance to fill in
            summary = TrackSummary(track)
            # Find the "Final results" marker for this track and then
            # search for individual metrics
            match = track_final_results_pattern.search( output )
            if match:
                # search the substring from the final results marker
                # for more specific stuff after this point
                final_results_section_start = match.start()
                summary.offered_load_ops_per_sec = \
                    float( track_offered_load_ops_pattern.search\
                             ( output, final_results_section_start ).group(1) )
                summary.effective_load_ops_per_sec = \
                    float( track_effective_load_ops_pattern.search\
                             ( output, final_results_section_start ).group(1) )
                summary.littles_estimate_ops_per_sec = \
                    float( track_littles_estimate_ops_pattern.search\
                             ( output, final_results_section_start ).group(1) )
                summary.effective_load_reqs_per_sec = \
                    float( track_effective_load_reqs_pattern.search\
                             ( output, final_results_section_start ).group(1) )
                summary.operations_successful = \
                    long( track_ops_successful_pattern.search\
                             ( output, final_results_section_start ).group(1) )
                summary.operations_failed = \
                    long( track_ops_failed_pattern.search\
                             ( output, final_results_section_start ).group(1) )
                summary.average_op_response_time_sec = \
                    float( track_avg_op_response_time_pattern.search\
                             ( output, final_results_section_start ).group(1) )
                summary.average_users = \
                    float( track_avg_users_pattern.search\
                             ( output, final_results_section_start ).group(1) )

                # find all the operations and print out the 90th and 99th
                # percentiles
                for opMatch in track_operation_pattern.\
                    finditer( output, final_results_section_start ):

                    #print opMatch
                    #print opMatch.group(0)
                    # Split group(0) on |
                    opCounters = opMatch.group(0).split( "|" )
                    #for s in opCounters:
                    #    print s
                    #print opCounters[1].strip(), opCounters[8], opCounters[9]
                    # Store the op name with a tuple (90th pct,99th pct)
                    summary.op_response_times[opCounters[1].strip()]=\
                        (float(opCounters[8].strip()), \
                             float(opCounters[9].strip()))
                #else:
                #   print "no operation match"

                # save the summary to the list we have so far
                #print summary.name, summary.op_response_times
                track_results.append(summary)

        # return the list of track results we found
        return track_results

    @staticmethod
    def print_results( results, output_stream=sys.stdout ):
        output_stream.write( RainOutputParser.RESULTS_HEADER + '\n' )
        for result in results:
            output_stream.write( str(result) + '\n' )
        # Flush the output stream
        output_stream.flush()

class RunManager():
    """
    A class for launching runs and validating results.
    """
    @staticmethod
    def run_rain( config_file="config/rain.config.ac.json", \
                  classpath=".:rain.jar:workloads/httptest.jar", \
                  min_heapsize="-Xms256m", \
                  max_heapsize="-Xmx1g", \
                  gc_policy="-XX:+DisableExplicitGC" ):
        """
        Launch process for Rain, get pid and then start querying
        sched stats
        """
        args = ["java", min_heapsize, max_heapsize, gc_policy, \
            "-cp", classpath, "radlab.rain.Benchmark", config_file  ]

        rain_process = None
        rain_process = subprocess.Popen(args, bufsize=-1, \
                                stdin=subprocess.PIPE, stdout=subprocess.PIPE)
        rain_pid = rain_process.pid
        print( "[Run manager] rain pid: %d" % rain_pid )

        # Sit and wait until Rain exits then parse the output
        # Return the raw output, clients can parse it themselves
        # or use the RainOutputParser to make sense
        # of it
        #output = rain_process.stdout.read()
        output, err = rain_process.communicate()
        return output

'''
Example command line
java -Xms256m -Xmx1g -XX:+DisableExplicitGC -cp .:rain.jar:workloads/httptest.jar radlab.rain.Benchmark config/rain.config.ac.json
'''

def run2():
    try:
        #results_file = open( "./rain.out", 'r' )
        results_file = open( "./rain.predictable.out", 'r' )
        results = results_file.read()
        track_results = RainOutputParser.parse_output( results )
        for result in track_results:
            # Set some 90th and 99th pctile thresholds
            result.op_response_time_thresholds['PingHome']=(0.001,0.005)

        RainOutputParser.print_results( track_results )
    #except:
    #    print "something broke"
    finally:
        if not results_file.closed:
            results_file.close()

def run3():

    config_file = "config/rain.config.ac.json"
    classpath = ".:rain.jar:workloads/httptest.jar"
    output = RunManager.run_rain(config_file, classpath)
    track_results = RainOutputParser.parse_output( output )
    RainOutputParser.print_results( track_results, sys.stdout )
    #return track_results

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


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

from django.conf import settings
from django.core.cache import cache
from django.utils import simplejson as json
from django.utils.http import cookie_date
from django.utils.translation import (
    get_language, get_language_info, ugettext as _
)
from django.utils.translation.trans_real import parse_accept_lang_header

from unilangs import get_language_name_mapping, LanguageCode

# A set of all language codes we support.
SUPPORTED_LANGUAGE_CODES = set(get_language_name_mapping('unisubs').keys())

def _only_supported_languages(language_codes):
    """Filter the given list of language codes to contain only codes we support."""

    # TODO: Figure out the codec issue here.
    return [code for code in language_codes if code in SUPPORTED_LANGUAGE_CODES]

def get_language_choices(with_empty=False, with_any=False):
    """Return a list of language code choices labeled appropriately."""

    cache_key = 'simple-langs-cache-%s' % get_language()
    languages = cache.get(cache_key)

    if not languages:
        languages = []

        for code, name in get_language_name_mapping('unisubs').items():
            languages.append((code, _(name)))

        languages.sort(key=lambda item: item[1])
        cache.set(cache_key, languages, 60*60)

    if with_any:
        languages = [('', _('--- Any Language ---'))] + languages

    if with_empty:
        languages = [('', '---------')] + languages

    return languages

def get_language_choices_as_dicts(with_empty=False):
    """Return a list of language code choices labeled appropriately."""
    return [
        {'code': code, 'name': name}
        for (code, name) in get_language_choices(with_empty)
    ]

def get_language_label(code):
    """Return the translated, human-readable label for the given language code."""
    lc = LanguageCode(code, 'unisubs')
    return u'%s' % _(lc.name())

def get_user_languages_from_request(request):
    """Return a list of our best guess at languages that request.user speaks."""
    languages = []

    if request.user.is_authenticated():
        languages = [l.language for l in request.user.get_languages()]

    if not languages:
        languages = languages_from_request(request)

    return _only_supported_languages(languages)

def set_user_languages_to_cookie(response, languages):
    max_age = 60*60*24
    response.set_cookie(
        settings.USER_LANGUAGES_COOKIE_NAME,
        json.dumps(languages),
        max_age=max_age,
        expires=cookie_date(time.time() + max_age))

def get_user_languages_from_cookie(request):
    try:
        langs = json.loads(request.COOKIES.get(settings.USER_LANGUAGES_COOKIE_NAME, '[]'))
        return _only_supported_languages(langs)
    except (TypeError, ValueError):
        return []

def languages_from_request(request):
    languages = []

    for l in get_user_languages_from_cookie(request):
        if not l in languages:
            languages.append(l)

    if not languages:
        trans_lang = get_language()
        if not trans_lang in languages:
            languages.append(trans_lang)

        if hasattr(request, 'session'):
            lang_code = request.session.get('django_language', None)
            if lang_code is not None and not lang_code in languages:
                languages.append(lang_code)

        cookie_lang_code = request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME)
        if cookie_lang_code and not cookie_lang_code in languages:
            languages.append(cookie_lang_code)

        accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '')
        for lang, val in parse_accept_lang_header(accept):
            if lang and lang != '*' and not lang in languages:
                languages.append(lang)

    return _only_supported_languages(languages)

def languages_with_labels(langs):
    """Return a dict of language codes to language labels for the given seq of codes.

    These codes must be in the internal unisubs format.

    The labels will be in the standard label format.

    """
    return dict([code, get_language_label(code)] for code in langs)

# This handles RTL info for languages where get_language_info() is not correct
_RTL_OVERRIDE_MAP = {
    # there are languages on our system that are not on django.
    'arq': True,
    'pnb': True,
    # Forcing Azerbaijani to be a left-to-right language.
    # For: https://unisubs.sifterapp.com/projects/12298/issues/753035/comments
    'az': False,
    # Force Urdu to be RTL (see gh-722)
    'ur': True,
    # Force Aramaic to be RTL (gh-1073)
    'arc': True,
}

def is_rtl(language_code):
    if language_code in _RTL_OVERRIDE_MAP:
        return _RTL_OVERRIDE_MAP[language_code]
    try:
        return get_language_info(language_code)['bidi']
    except KeyError:
        return False
<commit_msg>Flag Uyghur as an RTL language<commit_after># -*- coding: utf-8 -*-
import time

from django.conf import settings
from django.core.cache import cache
from django.utils import simplejson as json
from django.utils.http import cookie_date
from django.utils.translation import (
    get_language, get_language_info, ugettext as _
)
from django.utils.translation.trans_real import parse_accept_lang_header

from unilangs import get_language_name_mapping, LanguageCode

# A set of all language codes we support.
SUPPORTED_LANGUAGE_CODES = set(get_language_name_mapping('unisubs').keys())

def _only_supported_languages(language_codes):
    """Filter the given list of language codes to contain only codes we support."""

    # TODO: Figure out the codec issue here.
    return [code for code in language_codes if code in SUPPORTED_LANGUAGE_CODES]

def get_language_choices(with_empty=False, with_any=False):
    """Return a list of language code choices labeled appropriately."""

    cache_key = 'simple-langs-cache-%s' % get_language()
    languages = cache.get(cache_key)

    if not languages:
        languages = []

        for code, name in get_language_name_mapping('unisubs').items():
            languages.append((code, _(name)))

        languages.sort(key=lambda item: item[1])
        cache.set(cache_key, languages, 60*60)

    if with_any:
        languages = [('', _('--- Any Language ---'))] + languages

    if with_empty:
        languages = [('', '---------')] + languages

    return languages

def get_language_choices_as_dicts(with_empty=False):
    """Return a list of language code choices labeled appropriately."""
    return [
        {'code': code, 'name': name}
        for (code, name) in get_language_choices(with_empty)
    ]

def get_language_label(code):
    """Return the translated, human-readable label for the given language code."""
    lc = LanguageCode(code, 'unisubs')
    return u'%s' % _(lc.name())

def get_user_languages_from_request(request):
    """Return a list of our best guess at languages that request.user speaks."""
    languages = []

    if request.user.is_authenticated():
        languages = [l.language for l in request.user.get_languages()]

    if not languages:
        languages = languages_from_request(request)

    return _only_supported_languages(languages)

def set_user_languages_to_cookie(response, languages):
    max_age = 60*60*24
    response.set_cookie(
        settings.USER_LANGUAGES_COOKIE_NAME,
        json.dumps(languages),
        max_age=max_age,
        expires=cookie_date(time.time() + max_age))

def get_user_languages_from_cookie(request):
    try:
        langs = json.loads(request.COOKIES.get(settings.USER_LANGUAGES_COOKIE_NAME, '[]'))
        return _only_supported_languages(langs)
    except (TypeError, ValueError):
        return []

def languages_from_request(request):
    languages = []

    for l in get_user_languages_from_cookie(request):
        if not l in languages:
            languages.append(l)

    if not languages:
        trans_lang = get_language()
        if not trans_lang in languages:
            languages.append(trans_lang)

        if hasattr(request, 'session'):
            lang_code = request.session.get('django_language', None)
            if lang_code is not None and not lang_code in languages:
                languages.append(lang_code)

        cookie_lang_code = request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME)
        if cookie_lang_code and not cookie_lang_code in languages:
            languages.append(cookie_lang_code)

        accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '')
        for lang, val in parse_accept_lang_header(accept):
            if lang and lang != '*' and not lang in languages:
                languages.append(lang)

    return _only_supported_languages(languages)

def languages_with_labels(langs):
    """Return a dict of language codes to language labels for the given seq of codes.

    These codes must be in the internal unisubs format.

    The labels will be in the standard label format.

    """
    return dict([code, get_language_label(code)] for code in langs)

# This handles RTL info for languages where get_language_info() is not correct
_RTL_OVERRIDE_MAP = {
    # there are languages on our system that are not on django.
    'arq': True,
    'pnb': True,
    # Forcing Azerbaijani to be a left-to-right language.
    # For: https://unisubs.sifterapp.com/projects/12298/issues/753035/comments
    'az': False,
    # Force Urdu to be RTL (see gh-722)
    'ur': True,
    # Force Uyghur to be RTL (see gh-1411)
    'ug': True,
    # Force Aramaic to be RTL (gh-1073)
    'arc': True,
}

def is_rtl(language_code):
    if language_code in _RTL_OVERRIDE_MAP:
        return _RTL_OVERRIDE_MAP[language_code]
    try:
        return get_language_info(language_code)['bidi']
    except KeyError:
        return False
<|endoftext|>


<commit_before>import sys
from wsgiref.simple_server import WSGIRequestHandler

from .compat import BaseHTTPRequestHandler, TCPServer, get_content_type
from .curl import ask_uwsgi
from .utils import parse_addr

class RequestHandler(WSGIRequestHandler):
    handle = BaseHTTPRequestHandler.handle

    def write(self, s):
        self.wfile.write(s.encode('utf8'))
        self.close_connection = 1

    def do(self):
        self.log_message(self.requestline.rpartition(' ')[0]
                         .replace('%', '%%'))

        if self.server.redirect_static:
            if any(map(self.path.startswith, ['/static/', '/media/'])):
                return self.write('HTTP/1.1 302 Found\nLocation: http://%s%s\n'
                                  % (self.server.uwsgi_host, self.path))

        setattr(self.server, 'base_environ', {})
        env = WSGIRequestHandler.get_environ(self)
        qs = env['QUERY_STRING']
        env = dict(dict({
            'REQUEST_URI': env['PATH_INFO'] + (('?' + qs) if qs else ''),
            'CONTENT_LENGTH': '',
            'DOCUMENT_ROOT': '',
            'REMOTE_PORT': str(self.client_address[1]),
        }, **env), **{
            'SERVER_ADDR': self.server.uwsgi_addr,
            'SERVER_NAME': self.server.uwsgi_host,
            'SERVER_PORT': str(self.server.uwsgi_port),
            'CONTENT_TYPE': get_content_type(self.headers) or '',
            'HTTP_HOST': self.server.uwsgi_host,
        })
        env.pop('REMOTE_HOST', 0)
        env.pop('HTTP_REFERER', 0)

        cl = env['CONTENT_LENGTH']
        body = repr(self.rfile.read(int(cl))) if cl else ''

        resp = ask_uwsgi((self.server.uwsgi_addr, self.server.uwsgi_port),
                         var=env, body=body)
        self.write(resp)
        h, _, b = resp.partition('\r\n\r\n')
        print('%s\n%s' % (h, len(b)))

    do_HEAD = do_GET = do_POST = do

def serve_forever(uwsgi_addr, uwsgi_host=None, local_addr='',
                  redirect_static=True):

    uwsgi_addr, uwsgi_port = parse_addr(uwsgi_addr, 3030)
    local_addr = parse_addr(local_addr, uwsgi_port)

    print('Proxying remote uWSGI server %s:%s "%s" to local HTTP server '
          '%s:%s...' % (uwsgi_addr, uwsgi_port, (uwsgi_host or ''),
                        local_addr[0], local_addr[1]))

    TCPServer.allow_reuse_address = True
    s = TCPServer(
        server_address=parse_addr(local_addr),
        RequestHandlerClass=RequestHandler,
    )
    s.uwsgi_addr = uwsgi_addr
    s.uwsgi_port = uwsgi_port
    s.uwsgi_host = uwsgi_host or uwsgi_addr
    s.redirect_static = redirect_static
    try:
        s.serve_forever()
    except KeyboardInterrupt:
        s.shutdown()
        s.server_close()
        print(' Bye.')

def cli(*args):
    import argparse

    parser = argparse.ArgumentParser()

    parser.add_argument('uwsgi_addr', nargs=1,
                        help='Remote address of uWSGI server')
    parser.add_argument('-n', '--http-host',
                        help='HTTP_HOST header for uWSGI server')
    parser.add_argument('-l', '--local-addr', default='127.0.0.1',
                        help='Local address of HTTP server')
    parser.add_argument('-s', '--redirect-static', action='store_true',
                        default=False, help='Redirect static requests to host')

    args = parser.parse_args(args or sys.argv[1:])
    serve_forever(
        uwsgi_addr=args.uwsgi_addr[0],
        uwsgi_host=args.http_host,
        local_addr=args.local_addr,
        redirect_static=args.redirect_static,
    )

if __name__ == '__main__':
    cli()
<commit_msg>Shutdown proxy server in finally section.<commit_after>import sys
from wsgiref.simple_server import WSGIRequestHandler

from .compat import BaseHTTPRequestHandler, TCPServer, get_content_type
from .curl import ask_uwsgi
from .utils import parse_addr

class RequestHandler(WSGIRequestHandler):
    handle = BaseHTTPRequestHandler.handle

    def write(self, s):
        self.wfile.write(s.encode('utf8'))
        self.close_connection = True

    def do(self):
        self.log_message(self.requestline.rpartition(' ')[0]
                         .replace('%', '%%'))

        if self.server.redirect_static:
            if any(map(self.path.startswith, ['/static/', '/media/'])):
                return self.write('HTTP/1.1 302 Found\nLocation: http://%s%s\n'
                                  % (self.server.uwsgi_host, self.path))

        setattr(self.server, 'base_environ', {})
        env = WSGIRequestHandler.get_environ(self)
        qs = env['QUERY_STRING']
        env = dict(dict({
            'REQUEST_URI': env['PATH_INFO'] + (('?' + qs) if qs else ''),
            'CONTENT_LENGTH': '',
            'DOCUMENT_ROOT': '',
            'REMOTE_PORT': str(self.client_address[1]),
        }, **env), **{
            'SERVER_ADDR': self.server.uwsgi_addr,
            'SERVER_NAME': self.server.uwsgi_host,
            'SERVER_PORT': str(self.server.uwsgi_port),
            'CONTENT_TYPE': get_content_type(self.headers) or '',
            'HTTP_HOST': self.server.uwsgi_host,
        })
        env.pop('REMOTE_HOST', 0)
        env.pop('HTTP_REFERER', 0)

        cl = env['CONTENT_LENGTH']
        body = repr(self.rfile.read(int(cl))) if cl else ''

        resp = ask_uwsgi((self.server.uwsgi_addr, self.server.uwsgi_port),
                         var=env, body=body)
        self.write(resp)
        h, _, b = resp.partition('\r\n\r\n')
        print('%s\n%s' % (h, len(b)))

    do_HEAD = do_GET = do_POST = do

def serve_forever(uwsgi_addr, uwsgi_host=None, local_addr='',
                  redirect_static=True):

    uwsgi_addr, uwsgi_port = parse_addr(uwsgi_addr, 3030)
    local_addr = parse_addr(local_addr, uwsgi_port)

    print('Proxying remote uWSGI server %s:%s "%s" to local HTTP server '
          '%s:%s...' % (uwsgi_addr, uwsgi_port, (uwsgi_host or ''),
                        local_addr[0], local_addr[1]))

    TCPServer.allow_reuse_address = True
    s = TCPServer(
        server_address=parse_addr(local_addr),
        RequestHandlerClass=RequestHandler,
    )
    s.uwsgi_addr = uwsgi_addr
    s.uwsgi_port = uwsgi_port
    s.uwsgi_host = uwsgi_host or uwsgi_addr
    s.redirect_static = redirect_static
    try:
        s.serve_forever()
    except (KeyboardInterrupt, SystemExit):
        print(' Bye.')
    finally:
        s.shutdown()
        s.server_close()

def cli(*args):
    import argparse

    parser = argparse.ArgumentParser()

    parser.add_argument('uwsgi_addr', nargs=1,
                        help='Remote address of uWSGI server')
    parser.add_argument('-n', '--http-host',
                        help='HTTP_HOST header for uWSGI server')
    parser.add_argument('-l', '--local-addr', default='127.0.0.1',
                        help='Local address of HTTP server')
    parser.add_argument('-s', '--redirect-static', action='store_true',
                        default=False, help='Redirect static requests to host')

    args = parser.parse_args(args or sys.argv[1:])
    serve_forever(
        uwsgi_addr=args.uwsgi_addr[0],
        uwsgi_host=args.http_host,
        local_addr=args.local_addr,
        redirect_static=args.redirect_static,
    )

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


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

import urllib2
import httplib
import base64
import re

try:
    import xml.etree.cElementTree as ET
except (AttributeError, ImportError):
    import xml.etree.ElementTree as ET

class VCloudConn():
    """Example:
    conn = vcloudpy.VCloudConn(user, password, endpoint, debug=True)
    """

    def __init__(self, user, password, endpoint, protocol="https", api_version="5.1",
        path="/api", timeout=10, debug=False):
        """Initiallizes the VCloudConn class.

        Will automatically use parameters and establish connection to vCloud endpoint.

        Arguments:
        user -- vCloud userid in the form of user@orgid
        password -- vCloud user's password
        endpoint -- vCloud server endpoint, e.g. iad.vcloudservice.vmware.com
        protocol -- optional, http or https (default), most likely https
        api_version -- optional, usually either 5.1 (default) or 1.5
        path -- optional, api uri path, most likely don't change
        timeout -- optional, timeout in seconds for all http connections with vCloud, default 10
        debug -- optional, prints html responses from vCloud, True or False (default)
        """

        self.api_version = api_version
        self.timeout = timeout
        self.debug = debug
        self.base_url = "%s://%s%s" % (protocol.lower(), endpoint, path)

        # ok, we should be able to login now
        self._login(user, password)

    def _login(self, user, password):
        """Handles login duties, retrieves authorization token"""

        auth_url = self.base_url + "/sessions"
        req = urllib2.Request(auth_url)
        #auth = "Basic " + base64.urlsafe_b64encode("%s:%s" % (self.user, self.password))
        auth = "Basic " + base64.urlsafe_b64encode("%s:%s" % (user, password))
        req.add_header("Authorization", auth)
        req.get_method = lambda: "POST"

        # this should be in a try / except with more specific error messages
        result = self._send_request(req)
        self.auth_token = result.info().getheader("x-vcloud-authorization")

    def _xml_del_ns(self, xml):
        """A helper function that strips namespaces from xml text"""

        try:
            p = re.compile("xmlns=*[\"\"][^\"\"]*[\"\"]")
            allmatches = p.finditer(xml)
            for match in allmatches:
                xml = xml.replace(match.group(), "")
        except Exception as e:
            raise Exception(e)

        return xml

    def _make_request(self, url, verb, data=None, type=None):
        """Constructs the vCloud api request to send"""

        req = urllib2.Request(url)
        req.add_header("x-vcloud-authorization", self.auth_token)
        if type:
            req.add_header("Content-Type", type)
        req.get_method = lambda: verb
        if data:
            req.add_data(data)
        response = self._send_request(req)
        # out of laziness, we will strip the namespaces to make xpath work worry free
        return self._xml_del_ns(response.read())

    def _send_request(self, req):
        """Sends the request and handles errors"""

        req.add_header("Accept", "application/*+xml;version=%s" % self.api_version)
        # this should probably be in a incremental backoff loop if it times-out or certain error code returned
        try:
            response = urllib2.urlopen(req, timeout=self.timeout)
        except urllib2.HTTPError, e:
            raise Exception("HTTPError = %s, %s, %s\n%s" % (str(e.code), e.msg, e.read(), req.get_full_url()))
        except urllib2.URLError, e:
            raise Exception("URLError = %s\n%s" % (str(e.reason), req.get_full_url()))
        except httplib.HTTPException, e:
            raise Exception("HTTPException")
        except Exception:
            import traceback
            raise Exception("generic exception: " + traceback.format_exc())

        if self.debug:
            print response.info()
            r = response.read()
            print r

        return response

    def logout(self):
        """Handles the logout duties"""

        self.make_method_request("session", "DELETE")
        self.auth_token = None

    def make_href_request_path(self, href, verb="GET", data=None, type=None):
        """Used to retrieve an object using a full path"""

        return self._make_request(href, verb, data, type)

    def make_method_request(self, method, verb="GET"):
        """Used to make a method request."""

        full_url = self.base_url + "/" + method
        return self._make_request(full_url, verb)

    def get_node_values(self, xml, path, attribs=[], elems=[], other=""):
        """Given an xml string and path, returns a list of dictionary objects.

        Arguments:
        xml -- a string of properly formatted xml
        path -- an Xpath path.
                See http://docs.python.org/2/library/xml.etree.elementtree.html#supported-xpath-syntax
        attribs -- an optional list of xml node attribute names to retrieve the values for.
                "*" will retrieve all attributes per node found.
        elems -- an optional list of xml child elements to retrieve the text value for.
                "*" will retrieve all child elements per node found.
        other -- if the attribute or element is not found, return this value (e.g. "" or None)

        Example:

        print conn.get_node_values(z, "./NetworkConnection", elems=["MACAddress", "IpAddress"],
            attribs=["network", "needsCustomization", "aaaaaaaa"], other=None)

        Might return a list of two interfaces with the following dictionary values:

        [{'needsCustomization': 'false', 'aaaaaaaa': None, 'IpAddress': '212.54.150.58', 'network': 'Direct Internet connection', 'MACAddress': '00:50:56:01:02:eb'}, {'needsCustomization': 'false', 'aaaaaaaa': None, 'IpAddress': '212.54.150.82', 'network': 'Direct Internet connection', 'MACAddress': '00:50:56:01:02:e7'}]
        """

        result = []
        root = ET.fromstring(xml)
        if not path.startswith("./"):
            path = "./" + path
        nodes = root.findall(path)

        for n in nodes:
            node_result = {}
            if "*" in attribs:
                node_result = n.attrib
                # we don't care about the rest of the list, move on to elems
            else:
                for a in attribs:
                    if a in n.attrib.keys():
                        node_result[a] = n.attrib.get(a)
                    else:
                        node_result[a] = other
            if "*" in elems:
                for e in n:
                    node_result[e.tag] = e.text
                    # we don't care about the rest of the list, move on to the next node
            else:
                for e in elems:
                    node_result[e] = n.findtext(e, other)
            result.append(node_result)
        del(root)
        # don't forget: result will be a list, empty if path is not found
        return result

    #def get_node_attribs(self, path, xml):

    #    result = []
    #    root = ET.fromstring(xml)
    #    if not path.startswith("./"):
    #        path = "./" + path
    #    nodes = root.findall(path)
    #    for n in nodes:
    #        result.append(n.attrib)
    #    del(root)
    #    return result

    #def get_node_elements(self, xml, *args):

    #    return_list = []
    #    root = ET.fromstring(xml)
    #    for node in args:
    #        if not node.startswith("./"):
    #            node = "./" + node
    #        return_list.append(root.findtext(node, ""))
    #    del(root)
    #    return return_list

<commit_msg>moved get_node_values out of connection class<commit_after>#########################################################################
# Copyright 2013 Cloud Sidekick
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#########################################################################

import urllib2
import httplib
import base64
import re

try:
    import xml.etree.cElementTree as ET
except (AttributeError, ImportError):
    import xml.etree.ElementTree as ET

def get_node_values(xml, path, attribs=[], elems=[], other=""):
    """Given an xml string and path, returns a list of dictionary objects.

    Arguments:
    xml -- a string of properly formatted xml
    path -- an Xpath path.
            See http://docs.python.org/2/library/xml.etree.elementtree.html#supported-xpath-syntax
    attribs -- an optional list of xml node attribute names to retrieve the values for.
            "*" will retrieve all attributes per node found.
    elems -- an optional list of xml child elements to retrieve the text value for.
            "*" will retrieve all child elements per node found.
    other -- if the attribute or element is not found, return this value (e.g. "" or None)

    Example:

    print get_node_values(z, "./NetworkConnection", elems=["MACAddress", "IpAddress"],
        attribs=["network", "needsCustomization", "aaaaaaaa"], other=None)

    Might return a list of two interfaces with the following dictionary values:

    [{'needsCustomization': 'false', 'aaaaaaaa': None, 'IpAddress': '212.54.150.58', 'network': 'Direct Internet connection', 'MACAddress': '00:50:56:01:02:eb'}, {'needsCustomization': 'false', 'aaaaaaaa': None, 'IpAddress': '212.54.150.82', 'network': 'Direct Internet connection', 'MACAddress': '00:50:56:01:02:e7'}]
    """

    result = []
    root = ET.fromstring(xml)
    if not path.startswith("./"):
        path = "./" + path
    nodes = root.findall(path)

    for n in nodes:
        node_result = {}
        if "*" in attribs:
            node_result = n.attrib
            # we don't care about the rest of the list, move on to elems
        else:
            for a in attribs:
                if a in n.attrib.keys():
                    node_result[a] = n.attrib.get(a)
                else:
                    node_result[a] = other
        if "*" in elems:
            for e in n:
                node_result[e.tag] = e.text
                # we don't care about the rest of the list, move on to the next node
        else:
            for e in elems:
                node_result[e] = n.findtext(e, other)
        result.append(node_result)
    del(root)
    # don't forget: result will be a list, empty if path is not found
    return result

class VCloudConn():
    """Example:
    conn = vcloudpy.VCloudConn(user, password, endpoint, debug=True)
    """

    def __init__(self, user, password, endpoint, protocol="https", api_version="5.1",
        path="/api", timeout=10, debug=False):
        """Initiallizes the VCloudConn class.

        Will automatically use parameters and establish connection to vCloud endpoint.

        Arguments:
        user -- vCloud userid in the form of user@orgid
        password -- vCloud user's password
        endpoint -- vCloud server endpoint, e.g. iad.vcloudservice.vmware.com
        protocol -- optional, http or https (default), most likely https
        api_version -- optional, usually either 5.1 (default) or 1.5
        path -- optional, api uri path, most likely don't change
        timeout -- optional, timeout in seconds for all http connections with vCloud, default 10
        debug -- optional, prints html responses from vCloud, True or False (default)
        """

        self.api_version = api_version
        self.timeout = timeout
        self.debug = debug
        self.base_url = "%s://%s%s" % (protocol.lower(), endpoint, path)

        # ok, we should be able to login now
        self._login(user, password)

    def _login(self, user, password):
        """Handles login duties, retrieves authorization token"""

        auth_url = self.base_url + "/sessions"
        req = urllib2.Request(auth_url)
        #auth = "Basic " + base64.urlsafe_b64encode("%s:%s" % (self.user, self.password))
        auth = "Basic " + base64.urlsafe_b64encode("%s:%s" % (user, password))
        req.add_header("Authorization", auth)
        req.get_method = lambda: "POST"

        # this should be in a try / except with more specific error messages
        result = self._send_request(req)
        self.auth_token = result.info().getheader("x-vcloud-authorization")

    def _xml_del_ns(self, xml):
        """A helper function that strips namespaces from xml text"""

        try:
            p = re.compile("xmlns=*[\"\"][^\"\"]*[\"\"]")
            allmatches = p.finditer(xml)
            for match in allmatches:
                xml = xml.replace(match.group(), "")
        except Exception as e:
            raise Exception(e)

        return xml

    def _make_request(self, url, verb, data=None, type=None):
        """Constructs the vCloud api request to send"""

        req = urllib2.Request(url)
        req.add_header("x-vcloud-authorization", self.auth_token)
        if type:
            req.add_header("Content-Type", type)
        req.get_method = lambda: verb
        if data:
            req.add_data(data)
        response = self._send_request(req)
        # out of laziness, we will strip the namespaces to make xpath work worry free
        return self._xml_del_ns(response.read())

    def _send_request(self, req):
        """Sends the request and handles errors"""

        req.add_header("Accept", "application/*+xml;version=%s" % self.api_version)
        # this should probably be in a incremental backoff loop if it times-out or certain error code returned
        try:
            response = urllib2.urlopen(req, timeout=self.timeout)
        except urllib2.HTTPError, e:
            raise Exception("HTTPError = %s, %s, %s\n%s" % (str(e.code), e.msg, e.read(), req.get_full_url()))
        except urllib2.URLError, e:
            raise Exception("URLError = %s\n%s" % (str(e.reason), req.get_full_url()))
        except httplib.HTTPException, e:
            raise Exception("HTTPException")
        except Exception:
            import traceback
            raise Exception("generic exception: " + traceback.format_exc())

        if self.debug:
            print response.info()
            r = response.read()
            print r

        return response

    def logout(self):
        """Handles the logout duties"""

        self.make_method_request("session", "DELETE")
        self.auth_token = None

    def make_href_request_path(self, href, verb="GET", data=None, type=None):
        """Used to retrieve an object using a full path"""

        return self._make_request(href, verb, data, type)

    def make_method_request(self, method, verb="GET"):
        """Used to make a method request."""

        full_url = self.base_url + "/" + method
        return self._make_request(full_url, verb)

    #def get_node_attribs(self, path, xml):

    #    result = []
    #    root = ET.fromstring(xml)
    #    if not path.startswith("./"):
    #        path = "./" + path
    #    nodes = root.findall(path)
    #    for n in nodes:
    #        result.append(n.attrib)
    #    del(root)
    #    return result

    #def get_node_elements(self, xml, *args):

    #    return_list = []
    #    root = ET.fromstring(xml)
    #    for node in args:
    #        if not node.startswith("./"):
    #            node = "./" + node
    #        return_list.append(root.findtext(node, ""))
    #    del(root)
    #    return return_list

<|endoftext|>


<commit_before>from viaduct import db, application
from flask import render_template, Markup, redirect, url_for, abort,\
    flash
from flask.ext.login import current_user
import datetime
import re

from viaduct.api.group import GroupPermissionAPI
from viaduct.api.user import UserAPI
from viaduct.models import Group, User
from viaduct.models import Minute, Task
from viaduct.models.pimpy import TaskUserRel

DATE_FORMAT = application.config['DATE_FORMAT']

class PimpyAPI:
    @staticmethod
    def commit_minute_to_db(content, date, group_id):
        """
        Enter minute into the database.
        Return succes (boolean, message (string). Message is the new minute.id
        if succes is true, otherwise it contains an error message.
        """
        if not GroupPermissionAPI.can_write('pimpy'):
            abort(403)

        try:
            date = datetime.datetime.strptime(date, DATE_FORMAT)
        except:
            if date != "":
                return False, "Could not parse the date"
            date = None

        minute = Minute(content, group_id, date)
        db.session.add(minute)
        db.session.commit()

        return True, minute.id

    @staticmethod
    def commit_task_to_db(name, content, deadline, group_id, filled_in_users,
                          line, minute_id, status):
        """
        Enter task into the database.
        Return succes (boolean), message (string). Message is the new task.id
        if succes is true, otherwise it contains an error message.
        """
        if not GroupPermissionAPI.can_write('pimpy'):
            abort(403)

        if group_id == 'all':
            return False, "Group can not be 'all'"
        group = Group.query.filter(Group.id == group_id).first()
        if group is None:
            return False, "Could not distinguish group."

        users, message = PimpyAPI.get_list_of_users_from_string(
            group_id, filled_in_users)
        if not users:
            return False, message

        try:
            deadline = datetime.datetime.strptime(deadline, DATE_FORMAT)
        except:
            if deadline != "":
                return False, "Could not parse the deadline"
            deadline = None

        if minute_id <= 0:
            minute_id = 1

        task = Task(name, content, deadline, group_id,
                    users, minute_id, line, status)
        db.session.add(task)
        db.session.commit()
        return True, task.id

    @staticmethod
    def edit_task(task_id, name, content, deadline, group_id,
                  filled_in_users, line):
        """
        Returns succes (boolean), message (string). Message is irrelevant if
        succes is true, otherwise it contains what exactly went wrong.

        In case of succes the task is edited in the database.
        """
        if not GroupPermissionAPI.can_write('pimpy'):
            abort(403)

        if task_id == -1:
            return False, "no task_id given"

        task = Task.query.filter(Task.id == task_id).first()

        users, message = PimpyAPI.get_list_of_users_from_string(
            group_id, filled_in_users)
        if not users:
            return False, message

        if name:
            task.title = name
        if content:
            task.content = content
        if deadline:
            try:
                deadline = datetime.datetime.strptime(deadline, DATE_FORMAT)
            except:
                if deadline != "":
                    return False, "Could not parse the deadline"
                deadline = None
            task.deadline = deadline
        if group_id:
            task.group_id = group_id
        if line:
            task.line = line
        if users:
            task.users = users
    #   if status:
    #       task.status = status

        db.session.commit()
        return True, "task edited"

    @staticmethod
    def parse_minute(content, group_id, minute_id):
        """
        Parse the specified minutes for tasks and return them in a list.
        Same for DONE tasks and REMOVED tasks

        syntax within the content:
        ACTIE <name_1>, <name_2>, name_n>: <title of task>
        or
        TODO <name_1>, <name_2>, name_n>: <title of task>

        usage:
        tasks, dones, removes = parse_minute(content, group_id, minute_id)
        where content is a string with the entire minute
        group id is the group's id
        minute id is the minute's id
        """

        tasks_found = []
        dones_found = []
        removes_found = []

        regex = re.compile("\s*(?:ACTIE|TODO) ([^\n\r]*)")
        for i, line in enumerate(content.splitlines()):
            matches = regex.findall(line)
            for action in matches:
                try:
                    listed_users, title = action.split(":")
                except:
                    print("could not split the line on ':'.\nSkipping hit.")
                    flash("could not parse: " + action)
                    continue

                users, message = PimpyAPI.get_list_of_users_from_string(
                    group_id, listed_users)
                if not users:
                    print(message)
                    continue
                try:
                    task = Task(title, "", None, group_id, users,
                                minute_id, i, 0)
                except:
                    print("wasnt given the right input to create a task")
                    continue
                tasks_found.append(task)

        regex = re.compile("\s*(?:DONE) ([^\n\r]*)")
        matches = regex.findall(content)
        for done_id in matches:
            try:
                done_task = Task.query.filter(Task.id == done_id).first()
            except:
                print("could not find the given task")
                flash("could not find DONE " + done_id)
                continue
            if done_task:
                dones_found.append(done_task)
            else:
                print("Could not find task " + done_id)
                flash("could not find DONE " + done_id)

        regex = re.compile("\s*(?:REMOVE) ([^\n\r]*)")
        matches = regex.findall(content)
        for remove_id in matches:
            try:
                remove_task = Task.query.filter(Task.id == remove_id).first()
            except:
                print("could not find the given task")
                flash("could not find REMOVE " + remove_id)
                continue
            if remove_task:
                removes_found.append(remove_task)
            else:
                print("Could not find REMOVE " + remove_id)
                flash("could not find REMOVE " + remove_id)

        return tasks_found, dones_found, removes_found

    @staticmethod
    def get_list_of_users_from_string(group_id, comma_sep):
        """
        Parses a string which is a list of comma separated user names
        to a list of users, searching only within the group given

        Returns users, message. Users is false if there is something wrong,
        in which case the message is stated in message, otherwise message
        equals "" and users is the list of matched users

        usage:
        get_list_of_users_from_string(group_id, comma_sep)
        where group_id is the group's id
        and comma_sep is a string with comma seperated users.
        """
        if not GroupPermissionAPI.can_read('pimpy'):
            abort(403)

        group = Group.query.filter(Group.id == group_id).first()
        if group is None:
            return False, "Could not distinguish group."

        if comma_sep is None:
            return False, "Did not receive any comma separated users"

        comma_sep = map(lambda x: x.lower().strip(), comma_sep.split(','))

        found_users = []

        users = group.users.all()

        user_names = map(lambda x: "%s %s" % (x.first_name.lower().strip(),
                                              x.last_name.lower().strip()),
                         users)

        for comma_sep_user in comma_sep:

            temp_found_users = []
            for i in range(len(users)):

                # could use a filter here, but meh
                if user_names[i].startswith(comma_sep_user):
                    temp_found_users.append(users[i])

            if len(temp_found_users) == 0:
                # We want to add an action to all users if none has been found
                temp_found_users = users

            # We actually want to be able to add tasks to more than 1 user
            #if len(temp_found_users) > 1:
            #   return False, "could not disambiguate %s" % comma_sep_user

            found_users.extend(temp_found_users)
        return found_users, ""

    @staticmethod
    def get_navigation_menu(group_id, personal, type):
        if not GroupPermissionAPI.can_read('pimpy'):
            abort(403)
        if not current_user:
            flash('Current_user not found')
            return redirect(url_for('pimpy.view_minutes'))

        groups = current_user.groups.all()

        if not type:
            type = 'minutes'
        endpoint = 'pimpy.view_' + type
        endpoints = {'view_chosentype': endpoint,
                     'view_chosentype_personal': endpoint + '_personal',
                     'view_chosentype_chosenpersonal': endpoint +
                     ('_personal' if personal and type != 'minutes' else ''),
                     'view_tasks': 'pimpy.view_tasks',
                     'view_tasks_personal': 'pimpy.view_tasks_personal',
                     'view_tasks_chosenpersonal': 'pimpy.view_tasks',
                     'view_minutes': 'pimpy.view_minutes'}
        if personal:
            endpoints['view_tasks_chosenpersonal'] += '_personal'

        if not group_id:
            group_id = 'all'
        if group_id != 'all':
            group_id = int(group_id)

        return Markup(render_template('pimpy/api/side_menu.htm', groups=groups,
                                      group_id=group_id, personal=personal,
                                      type=type, endpoints=endpoints))

    @staticmethod
    def get_all_tasks(group_id):
        """
        Shows all tasks ever made.
        Can specify specific group.
        No internal permission system made yet.
        Do not make routes to this module yet.
        """
        if not GroupPermissionAPI.can_read('pimpy'):
            abort(403)
        if not current_user:
            flash('Current_user not found')
            return redirect(url_for('pimpy.view_tasks'))

        status_meanings = Task.get_status_meanings()

        list_items = {}
        if group_id == 'all':
            for group in UserAPI.get_groups_for_current_user():
                list_users = {}
                list_users['Iedereen'] = group.tasks
                list_items[group.name] = list_users
        else:
            list_users = {}
            tasks = Task.query.filter(Task.group_id == group_id).all()
            group = Group.query.filter(Group.id == group_id).first()
            if not group:
                abort(404)
            if not group in UserAPI.get_groups_for_current_user():
                abort(403)
            list_users['Iedereen'] = tasks
            list_items[group.name] = list_users

        return Markup(render_template('pimpy/api/tasks.htm',
                                      list_items=list_items, type='tasks',
                                      group_id=group_id, personal=False,
                                      status_meanings=status_meanings))

    @staticmethod
    def get_tasks(group_id, personal):
        if not GroupPermissionAPI.can_read('pimpy'):
            abort(403)
        if not current_user:
            flash('Current_user not found')
            return redirect(url_for('pimpy.view_tasks'))

        status_meanings = Task.get_status_meanings()

        tasks_rel = TaskUserRel.query.join(Task).join(User)

        groups = UserAPI.get_groups_for_current_user()
        groups = map(lambda x: x.id, groups)

        if group_id == 'all':
            tasks_rel = tasks_rel.filter(Task.group_id.in_(groups))

        else:
            group_id = int(group_id)
            if group_id not in groups:
                abort(403)

            tasks_rel = tasks_rel.filter(Task.group_id == group_id)

        if personal:
            tasks_rel = tasks_rel.filter(User.id == current_user.id)

        tasks_rel = tasks_rel.filter(~Task.status.in_((4, 5))).join(Group)
        tasks_rel = tasks_rel.order_by(Group.name.asc(), User.first_name.asc(),
                                       User.last_name.asc(), Task.id.asc())

        return Markup(render_template('pimpy/api/tasks.htm',
                                      personal=personal,
                                      tasks_rel=tasks_rel,
                                      type='tasks',
                                      status_meanings=status_meanings))

    @staticmethod
    def get_minutes(group_id):
        """
        Load all minutes in the given group
        """
        if not GroupPermissionAPI.can_read('pimpy'):
            abort(403)
        if not current_user:
            flash('Current_user not found')
            return redirect(url_for('pimpy.view_minutes'))

        list_items = {}

        if group_id != 'all':
            query = Minute.query.filter(Minute.group_id == group_id).\
                order_by(Minute.minute_date.desc())
            list_items[Group.query.filter(Group.id == group_id).first().name]\
                = query.all()
        # this should be done with a sql in statement, or something, but meh
        else:
            for group in current_user.groups:
                query = Minute.query.filter(Minute.group_id == group.id)
                query = query.order_by(Minute.minute_date.desc())
                list_items[group.name] = query.all()

        return Markup(render_template('pimpy/api/minutes.htm',
                                      list_items=list_items, type='minutes',
                                      group_id=group_id))

    @staticmethod
    def get_minute(group_id, minute_id):
        """
        Load (and thus view) specifically one minute
        """
        if not GroupPermissionAPI.can_read('pimpy'):
            abort(403)
        if not current_user:
            flash('Current_user not found')
            return redirect(url_for('pimpy.view_minutes'))

        list_items = {}
        query = Minute.query.filter(Minute.id == minute_id)
        group = Group.query.filter(Group.id == group_id).first()
        list_items[group.name] = query.all()

        return Markup(render_template('pimpy/api/minutes.htm',
                                      list_items=list_items, type='minutes',
                                      group_id=group_id))

    @staticmethod
    def update_content(task_id, content):
        """
        Update the content of the task with the given id
        """
        task = Task.query.filter(Task.id == task_id).first()
        task.content = content
        db.session.commit()
        return True, "The task is edited sucessfully"

    @staticmethod
    def update_title(task_id, title):
        """
        Update the title of the task with the given id
        """
        task = Task.query.filter(Task.id == task_id).first()
        task.title = title
        db.session.commit()
        return True, "The task is edited sucessfully"

    @staticmethod
    def update_users(task_id, comma_sep_users):
        """
        Update the users of the task with the given id
        """
        task = Task.query.filter(Task.id == task_id).first()
        users, message = PimpyAPI.get_list_of_users_from_string(
            task.group_id, comma_sep_users)
        if not users:
            return False, message
        task.users = users
        db.session.commit()
        return True, "The task is edited sucessfully"

    @staticmethod
    def update_date(task_id, date):
        """
        Update the date of the task with the given id
        """
        try:
            date = datetime.datetime.strptime(date, DATE_FORMAT)
        except:
            if date != "":
                return False, "Could not parse the date"
            date = None

        task = Task.query.filter(Task.id == task_id).first()
        task.deadline = date
        db.session.commit()
        return True, "The task is edited sucessfully"
<commit_msg>Fix highlight of selected group<commit_after>from viaduct import db, application
from flask import render_template, Markup, redirect, url_for, abort,\
    flash
from flask.ext.login import current_user
import datetime
import re

from viaduct.api.group import GroupPermissionAPI
from viaduct.api.user import UserAPI
from viaduct.models import Group, User
from viaduct.models import Minute, Task
from viaduct.models.pimpy import TaskUserRel

DATE_FORMAT = application.config['DATE_FORMAT']

class PimpyAPI:
    @staticmethod
    def commit_minute_to_db(content, date, group_id):
        """
        Enter minute into the database.
        Return succes (boolean, message (string). Message is the new minute.id
        if succes is true, otherwise it contains an error message.
        """
        if not GroupPermissionAPI.can_write('pimpy'):
            abort(403)

        try:
            date = datetime.datetime.strptime(date, DATE_FORMAT)
        except:
            if date != "":
                return False, "Could not parse the date"
            date = None

        minute = Minute(content, group_id, date)
        db.session.add(minute)
        db.session.commit()

        return True, minute.id

    @staticmethod
    def commit_task_to_db(name, content, deadline, group_id, filled_in_users,
                          line, minute_id, status):
        """
        Enter task into the database.
        Return succes (boolean), message (string). Message is the new task.id
        if succes is true, otherwise it contains an error message.
        """
        if not GroupPermissionAPI.can_write('pimpy'):
            abort(403)

        if group_id == 'all':
            return False, "Group can not be 'all'"
        group = Group.query.filter(Group.id == group_id).first()
        if group is None:
            return False, "Could not distinguish group."

        users, message = PimpyAPI.get_list_of_users_from_string(
            group_id, filled_in_users)
        if not users:
            return False, message

        try:
            deadline = datetime.datetime.strptime(deadline, DATE_FORMAT)
        except:
            if deadline != "":
                return False, "Could not parse the deadline"
            deadline = None

        if minute_id <= 0:
            minute_id = 1

        task = Task(name, content, deadline, group_id,
                    users, minute_id, line, status)
        db.session.add(task)
        db.session.commit()
        return True, task.id

    @staticmethod
    def edit_task(task_id, name, content, deadline, group_id,
                  filled_in_users, line):
        """
        Returns succes (boolean), message (string). Message is irrelevant if
        succes is true, otherwise it contains what exactly went wrong.

        In case of succes the task is edited in the database.
        """
        if not GroupPermissionAPI.can_write('pimpy'):
            abort(403)

        if task_id == -1:
            return False, "no task_id given"

        task = Task.query.filter(Task.id == task_id).first()

        users, message = PimpyAPI.get_list_of_users_from_string(
            group_id, filled_in_users)
        if not users:
            return False, message

        if name:
            task.title = name
        if content:
            task.content = content
        if deadline:
            try:
                deadline = datetime.datetime.strptime(deadline, DATE_FORMAT)
            except:
                if deadline != "":
                    return False, "Could not parse the deadline"
                deadline = None
            task.deadline = deadline
        if group_id:
            task.group_id = group_id
        if line:
            task.line = line
        if users:
            task.users = users
    #   if status:
    #       task.status = status

        db.session.commit()
        return True, "task edited"

    @staticmethod
    def parse_minute(content, group_id, minute_id):
        """
        Parse the specified minutes for tasks and return them in a list.
        Same for DONE tasks and REMOVED tasks

        syntax within the content:
        ACTIE <name_1>, <name_2>, name_n>: <title of task>
        or
        TODO <name_1>, <name_2>, name_n>: <title of task>

        usage:
        tasks, dones, removes = parse_minute(content, group_id, minute_id)
        where content is a string with the entire minute
        group id is the group's id
        minute id is the minute's id
        """

        tasks_found = []
        dones_found = []
        removes_found = []

        regex = re.compile("\s*(?:ACTIE|TODO) ([^\n\r]*)")
        for i, line in enumerate(content.splitlines()):
            matches = regex.findall(line)
            for action in matches:
                try:
                    listed_users, title = action.split(":")
                except:
                    print("could not split the line on ':'.\nSkipping hit.")
                    flash("could not parse: " + action)
                    continue

                users, message = PimpyAPI.get_list_of_users_from_string(
                    group_id, listed_users)
                if not users:
                    print(message)
                    continue
                try:
                    task = Task(title, "", None, group_id, users,
                                minute_id, i, 0)
                except:
                    print("wasnt given the right input to create a task")
                    continue
                tasks_found.append(task)

        regex = re.compile("\s*(?:DONE) ([^\n\r]*)")
        matches = regex.findall(content)
        for done_id in matches:
            try:
                done_task = Task.query.filter(Task.id == done_id).first()
            except:
                print("could not find the given task")
                flash("could not find DONE " + done_id)
                continue
            if done_task:
                dones_found.append(done_task)
            else:
                print("Could not find task " + done_id)
                flash("could not find DONE " + done_id)

        regex = re.compile("\s*(?:REMOVE) ([^\n\r]*)")
        matches = regex.findall(content)
        for remove_id in matches:
            try:
                remove_task = Task.query.filter(Task.id == remove_id).first()
            except:
                print("could not find the given task")
                flash("could not find REMOVE " + remove_id)
                continue
            if remove_task:
                removes_found.append(remove_task)
            else:
                print("Could not find REMOVE " + remove_id)
                flash("could not find REMOVE " + remove_id)

        return tasks_found, dones_found, removes_found

    @staticmethod
    def get_list_of_users_from_string(group_id, comma_sep):
        """
        Parses a string which is a list of comma separated user names
        to a list of users, searching only within the group given

        Returns users, message. Users is false if there is something wrong,
        in which case the message is stated in message, otherwise message
        equals "" and users is the list of matched users

        usage:
        get_list_of_users_from_string(group_id, comma_sep)
        where group_id is the group's id
        and comma_sep is a string with comma seperated users.
        """
        if not GroupPermissionAPI.can_read('pimpy'):
            abort(403)

        group = Group.query.filter(Group.id == group_id).first()
        if group is None:
            return False, "Could not distinguish group."

        if comma_sep is None:
            return False, "Did not receive any comma separated users"

        comma_sep = map(lambda x: x.lower().strip(), comma_sep.split(','))

        found_users = []

        users = group.users.all()

        user_names = map(lambda x: "%s %s" % (x.first_name.lower().strip(),
                                              x.last_name.lower().strip()),
                         users)

        for comma_sep_user in comma_sep:

            temp_found_users = []
            for i in range(len(users)):

                # could use a filter here, but meh
                if user_names[i].startswith(comma_sep_user):
                    temp_found_users.append(users[i])

            if len(temp_found_users) == 0:
                # We want to add an action to all users if none has been found
                temp_found_users = users

            # We actually want to be able to add tasks to more than 1 user
            #if len(temp_found_users) > 1:
            #   return False, "could not disambiguate %s" % comma_sep_user

            found_users.extend(temp_found_users)
        return found_users, ""

    @staticmethod
    def get_navigation_menu(group_id, personal, type):
        if not GroupPermissionAPI.can_read('pimpy'):
            abort(403)
        if not current_user:
            flash('Current_user not found')
            return redirect(url_for('pimpy.view_minutes'))

        groups = current_user.groups.all()

        if not type:
            type = 'minutes'
        endpoint = 'pimpy.view_' + type
        endpoints = {'view_chosentype': endpoint,
                     'view_chosentype_personal': endpoint + '_personal',
                     'view_chosentype_chosenpersonal': endpoint +
                     ('_personal' if personal and type != 'minutes' else ''),
                     'view_tasks': 'pimpy.view_tasks',
                     'view_tasks_personal': 'pimpy.view_tasks_personal',
                     'view_tasks_chosenpersonal': 'pimpy.view_tasks',
                     'view_minutes': 'pimpy.view_minutes'}
        if personal:
            endpoints['view_tasks_chosenpersonal'] += '_personal'

        if not group_id:
            group_id = 'all'
        if group_id != 'all':
            group_id = int(group_id)

        return Markup(render_template('pimpy/api/side_menu.htm', groups=groups,
                                      group_id=group_id, personal=personal,
                                      type=type, endpoints=endpoints))

    @staticmethod
    def get_all_tasks(group_id):
        """
        Shows all tasks ever made.
        Can specify specific group.
        No internal permission system made yet.
        Do not make routes to this module yet.
        """
        if not GroupPermissionAPI.can_read('pimpy'):
            abort(403)
        if not current_user:
            flash('Current_user not found')
            return redirect(url_for('pimpy.view_tasks'))

        status_meanings = Task.get_status_meanings()

        list_items = {}
        if group_id == 'all':
            for group in UserAPI.get_groups_for_current_user():
                list_users = {}
                list_users['Iedereen'] = group.tasks
                list_items[group.name] = list_users
        else:
            list_users = {}
            tasks = Task.query.filter(Task.group_id == group_id).all()
            group = Group.query.filter(Group.id == group_id).first()
            if not group:
                abort(404)
            if not group in UserAPI.get_groups_for_current_user():
                abort(403)
            list_users['Iedereen'] = tasks
            list_items[group.name] = list_users

        return Markup(render_template('pimpy/api/tasks.htm',
                                      list_items=list_items, type='tasks',
                                      group_id=group_id, personal=False,
                                      status_meanings=status_meanings))

    @staticmethod
    def get_tasks(group_id, personal):
        if not GroupPermissionAPI.can_read('pimpy'):
            abort(403)
        if not current_user:
            flash('Current_user not found')
            return redirect(url_for('pimpy.view_tasks'))

        status_meanings = Task.get_status_meanings()

        tasks_rel = TaskUserRel.query.join(Task).join(User)

        groups = UserAPI.get_groups_for_current_user()
        groups = map(lambda x: x.id, groups)

        if group_id == 'all':
            tasks_rel = tasks_rel.filter(Task.group_id.in_(groups))

        else:
            group_id = int(group_id)
            if group_id not in groups:
                abort(403)

            tasks_rel = tasks_rel.filter(Task.group_id == group_id)

        if personal:
            tasks_rel = tasks_rel.filter(User.id == current_user.id)

        tasks_rel = tasks_rel.filter(~Task.status.in_((4, 5))).join(Group)
        tasks_rel = tasks_rel.order_by(Group.name.asc(), User.first_name.asc(),
                                       User.last_name.asc(), Task.id.asc())

        return Markup(render_template('pimpy/api/tasks.htm',
                                      personal=personal,
                                      group_id=group_id,
                                      tasks_rel=tasks_rel,
                                      type='tasks',
                                      status_meanings=status_meanings))

    @staticmethod
    def get_minutes(group_id):
        """
        Load all minutes in the given group
        """
        if not GroupPermissionAPI.can_read('pimpy'):
            abort(403)
        if not current_user:
            flash('Current_user not found')
            return redirect(url_for('pimpy.view_minutes'))

        list_items = {}

        if group_id != 'all':
            query = Minute.query.filter(Minute.group_id == group_id).\
                order_by(Minute.minute_date.desc())
            list_items[Group.query.filter(Group.id == group_id).first().name]\
                = query.all()
        # this should be done with a sql in statement, or something, but meh
        else:
            for group in current_user.groups:
                query = Minute.query.filter(Minute.group_id == group.id)
                query = query.order_by(Minute.minute_date.desc())
                list_items[group.name] = query.all()

        return Markup(render_template('pimpy/api/minutes.htm',
                                      list_items=list_items, type='minutes',
                                      group_id=group_id))

    @staticmethod
    def get_minute(group_id, minute_id):
        """
        Load (and thus view) specifically one minute
        """
        if not GroupPermissionAPI.can_read('pimpy'):
            abort(403)
        if not current_user:
            flash('Current_user not found')
            return redirect(url_for('pimpy.view_minutes'))

        list_items = {}
        query = Minute.query.filter(Minute.id == minute_id)
        group = Group.query.filter(Group.id == group_id).first()
        list_items[group.name] = query.all()

        return Markup(render_template('pimpy/api/minutes.htm',
                                      list_items=list_items, type='minutes',
                                      group_id=group_id))

    @staticmethod
    def update_content(task_id, content):
        """
        Update the content of the task with the given id
        """
        task = Task.query.filter(Task.id == task_id).first()
        task.content = content
        db.session.commit()
        return True, "The task is edited sucessfully"

    @staticmethod
    def update_title(task_id, title):
        """
        Update the title of the task with the given id
        """
        task = Task.query.filter(Task.id == task_id).first()
        task.title = title
        db.session.commit()
        return True, "The task is edited sucessfully"

    @staticmethod
    def update_users(task_id, comma_sep_users):
        """
        Update the users of the task with the given id
        """
        task = Task.query.filter(Task.id == task_id).first()
        users, message = PimpyAPI.get_list_of_users_from_string(
            task.group_id, comma_sep_users)
        if not users:
            return False, message
        task.users = users
        db.session.commit()
        return True, "The task is edited sucessfully"

    @staticmethod
    def update_date(task_id, date):
        """
        Update the date of the task with the given id
        """
        try:
            date = datetime.datetime.strptime(date, DATE_FORMAT)
        except:
            if date != "":
                return False, "Could not parse the date"
            date = None

        task = Task.query.filter(Task.id == task_id).first()
        task.deadline = date
        db.session.commit()
        return True, "The task is edited sucessfully"
<|endoftext|>