<commit_before>#!/usr/bin/env python
DESC = """EPP script for Quant-iT mesurements to verify standards, calculate
concentrations and load input artifact-udfs and output file-udfs of the process
with concentation values and fluorescence intensity

Reads from:
    --Lims fields--
    "Assay type"                process udf
    "Standard volume"           process udf
    "Standard dilution"         process udf
    "Linearity of standards"    process udf
    "Sample volume"             process udf

    --files--
    "Standards File (.txt)"     "shared result file" uploaded by user.
    "Quant-iT Result File 1"    "shared result file" uploaded by user.
    "Quant-iT Result File 2"    "shared result file" uploaded by user. (optional)

Writes to:
    --Lims fields--
    "Fluorescence intensity 1"  udf of input analytes to the process
    "Fluorescence intensity 2"  udf of input analytes to the  process
    "Concentration"             udf of process artifacts (result file)
    "Conc. Units"               udf of process artifacts (result file)

Logging:
The script outputs a regular log file with regular execution information.

Performance:
1)  Makes a linear regression analysis on the End RFU standards read from
"Standards File (.txt)" --> slope, intersect and R2 (Pearson correlation coefficient)

2)  If R2 is less than "Linearity of standards", standards are not ok and the
user is warned "Problem with standards! Redo measurement!".

3)  If R2 is greater than "Linearity of standards", concentration values are
calculated based on the linear regression parameters, copied to the "Concentration"-udf
on the output artifacts (one result file per sample). The "Conc. Units"-udf on the same
artifacts are set to "ng/ul".

4)  "End RFU" values from "Quant-iT Result File 1" are copied to the udf
"Fluorescence intentisy 1" of the input analyte to the process, and "End RFU" values from
"Quant-iT Result File 2" are copied to the udf "Fluorescence intensity 2".

Written by Maya Brandi
"""

import os
import sys
import logging
import numpy as np

from argparse import ArgumentParser
from requests import HTTPError
from genologics.lims import Lims
from genologics.config import BASEURI,USERNAME,PASSWORD
from genologics.entities import Process
from genologics.epp import EppLogger
from genologics.epp import set_field
from genologics.epp import ReadResultFiles
lims = Lims(BASEURI,USERNAME,PASSWORD)

class QunatiT():
    def __init__(self, process):
        self.file_handler = ReadResultFiles(process)
        self.udfs = dict(process.udf.items())
        self.abstract = []
        self.missing_udfs = []
        self.missing_samps =[]
        self.no_samps = 0
        self.standards = self._make_standards_dict()
        self.model = self._verify_standards()
        self.result_files = self._formated_result_files_dict()

    def _formated_result_files_dict(self):
        """"Quant-iT Result File 1" and "Quant-iT Result File 2" (the second is optional)
        uploaded by user, are formated and stored in a dict"""
        result_files_dict = {}
        file_names = {'Quant-iT Result File 1':'Fluorescence intensity 1',
                    'Quant-iT Result File 2':'Fluorescence intensity 2'}
        for f_name, udf_name in file_names.items():
            if self.file_handler.shared_files.has_key(f_name):
                result_file = self.file_handler.shared_files[f_name]
                result_files_dict[udf_name] = self.file_handler.format_file(result_file,
                                            name = f_name, root_key_col = 1, header_row = 19)
        return result_files_dict

    def _make_standards_dict(self):
        """End RFU standards are read from 'Standards File (.txt)' and stored in a dict"""
        standards_file = self.file_handler.shared_files['Standards File (.txt)']
        standards_file_formated = self.file_handler.format_file(standards_file,
                        name = 'Standards File (.txt)', root_key_col = 1, header_row = 19)
        standards_dict = {}
        for k,v in standards_file_formated.items():
            if set(['Sample','End RFU']).issubset(v) and v['Sample'].split()[0]=='Standard':
                standard = int(v['Sample'].split()[1])
                standards_dict[standard] = float(v['End RFU'])
        return standards_dict

    def _nuclear_acid_amount_in_standards(self):
        """Nuclear acid amount in standards is calculated as
        "Supposed concentrations of standards" * "Standard volume" / "Standard dilution"
        Supposed concentrations of standards are different between Quant-iT BR
        assays and Quant-iT HS assays."""
        requiered_udfs = set(['Standard volume','Assay type','Standard dilution'])
        supp_conc_stds = {'RNA BR':[0,5,10,20,40,60,80,100],
                          'DNA BR':[0,5,10,20,40,60,80,100],
                          'RNA':[0,0.5,1,2,4,6,8,10],
                          'DNA HS':[0,0.5,1,2,4,6,8,10]}
        if requiered_udfs.issubset(self.udfs.keys()):
            nuclear_acid_amount = np.ones(8)
            for standard in range(8):
                supp_conc_standard = supp_conc_stds[self.udfs['Assay type']][standard]
                nuclear_acid_amount[standard] = np.true_divide(supp_conc_standard *
                                    self.udfs['Standard volume'], self.udfs['Standard dilution'])
            return nuclear_acid_amount
        elif not requiered_udfs.issubset(self.missing_udfs):
            self.missing_udfs += requiered_udfs
        return None

    def _linear_regression(self, X,Y):
        """Perform linear regression with intersect forced to origin. And calculates
        Pearson correlation coefficient R2. """
        X = np.array(X)
        X_force_zero = X[:,np.newaxis]
        slope = np.linalg.lstsq(X_force_zero, Y)[0]

        A = np.array([ X, np.ones(len(X))])
        resid = np.linalg.lstsq(A.T,Y)[1]
        R2 = 1 - resid / (Y.size * Y.var())
        return float(R2), float(slope)

    def _verify_standards(self):
        """Performing linear regresion on standards.
        X = Relative fluorescence intensities of 8 standards
        Y = Nuclear acid amount in standards
        Y = slope*X + intersect; R2=Pearson correlation coefficient."""
        amount_in_standards = self._nuclear_acid_amount_in_standards()
        if amount_in_standards is not None:
            relative_standards = np.ones(8)
            for k,v in self.standards.items():
                relative_standards[k-1] = v - self.standards[1]
            R2, slope = self._linear_regression(relative_standards, amount_in_standards)
            return [R2, slope]
        else:
            return None

    def get_and_set_fluor_int(self, target_file):
        """Copies "End RFU" values from "Quant-iT Result File 1" and "Quant-iT Result File 2"
        (if provided) to udfs "Fluorescence intentisy 1" and "Fluorescence intensity 2.
        Calculates and returns Relative fluorescence intensitiy standards:
        rel_fluor_int = The End RFU of standards - Background fluorescence intensity"""
        sample = target_file.samples[0].name
        fluor_int = []
        target_file.udf.__delitem__("Fluorescence intentisy 1")
        target_file.udf.__delitem__("Fluorescence intentisy 2")
        for udf_name ,formated_file in self.result_files.items():
            if sample in formated_file.keys():
                fluor_int.append(int(formated_file[sample]['End RFU']))
                target_file.udf[udf_name] = int(formated_file[sample]['End RFU'])
            else:
                self.missing_samps.append(sample)
        set_field(target_file)
        rel_fluor_int = np.mean(fluor_int) - self.standards[1]
        return rel_fluor_int

    def calc_and_set_conc(self, target_file, rel_fluor_int):
        """Concentrations are calculated based on the linear regression parametersand copied to
        the "Concentration"-udf of the target_file. The "Conc. Units"-udf is set to "ng/ul"""
        requiered_udfs = set(['Sample volume','Standard dilution','WS volume'])
        if requiered_udfs.issubset(self.udfs.keys()) and self.model:
            conc = np.true_divide((self.model[1] * rel_fluor_int * (self.udfs['WS volume'] +
            self.udfs['Sample volume'])),self.udfs['Sample volume']*(self.udfs['WS volume'] +
                                                                self.udfs['Standard volume']))
            target_file.udf['Concentration'] = conc
            target_file.udf['Conc. Units'] = 'ng/ul'
            set_field(target_file)
            self.no_samps +=1
        elif not requiered_udfs.issubset(self.missing_udfs):
            self.missing_udfs += requiered_udfs

def main(lims, pid, epp_logger):
    process = Process(lims,id = pid)
    QiT = QunatiT(process)
    target_files = dict((r.samples[0].name, r) for r in process.result_files())
    if QiT.model and 'Linearity of standards' in QiT.udfs.keys():
        R2 = QiT.model[0]
        if R2 >= QiT.udfs['Linearity of standards']:
            QiT.abstract.insert(0,"R2 = {0}. Standards OK.".format(R2))
            if QiT.result_files:
                for sample, target_file in target_files.items():
                    rel_fluor_int = QiT.get_and_set_fluor_int(target_file)
                    QiT.calc_and_set_conc(target_file, rel_fluor_int)
                QiT.abstract.append("Concentrations uploaded for {0} samples.".format(QiT.no_samps))
            else:
                QiT.abstract.append("Upload input file(s) for samples.")
        else:
            QiT.abstract.insert(0, "R2 = {0}. Problem with standards! Redo measurement!".format(R2))
    else:
        QiT.missing_udfs.append('Linearity of standards')
    if QiT.missing_samps:
        QiT.abstract.append("The folowing samples are missing in Quant-iT result File 1 or 2: {0}.".format(
                                                                            ', '.join(QiT.missing_samps)))

    if QiT.missing_udfs:
        QiT.abstract.append("Are all of the folowing udfs set? : {0}".format(', '.join(QiT.missing_udfs)))

    print >> sys.stderr, ' '.join(QiT.abstract)

if __name__ == "__main__":
    parser = ArgumentParser(description=DESC)
    parser.add_argument('--pid', default = None , dest = 'pid',
                        help='Lims id for current Process')
    parser.add_argument('--log', dest = 'log',
                        help=('File name for standard log file, '
                              'for runtime information and problems.'))

    args = parser.parse_args()
    lims = Lims(BASEURI,USERNAME,PASSWORD)
    lims.check_version()

    with EppLogger(log_file=args.log, lims=lims, prepend=True) as epp_logger:
        main(lims, args.pid, epp_logger)

<commit_msg>rm old flourecence intencity from udf if not given as input<commit_after>#!/usr/bin/env python
DESC = """EPP script for Quant-iT mesurements to verify standards, calculate
concentrations and load input artifact-udfs and output file-udfs of the process
with concentation values and fluorescence intensity

Reads from:
    --Lims fields--
    "Assay type"                process udf
    "Standard volume"           process udf
    "Standard dilution"         process udf
    "Linearity of standards"    process udf
    "Sample volume"             process udf

    --files--
    "Standards File (.txt)"     "shared result file" uploaded by user.
    "Quant-iT Result File 1"    "shared result file" uploaded by user.
    "Quant-iT Result File 2"    "shared result file" uploaded by user. (optional)

Writes to:
    --Lims fields--
    "Fluorescence intensity 1"  udf of input analytes to the process
    "Fluorescence intensity 2"  udf of input analytes to the  process
    "Concentration"             udf of process artifacts (result file)
    "Conc. Units"               udf of process artifacts (result file)

Logging:
The script outputs a regular log file with regular execution information.

Performance:
1)  Makes a linear regression analysis on the End RFU standards read from
"Standards File (.txt)" --> slope, intersect and R2 (Pearson correlation coefficient)

2)  If R2 is less than "Linearity of standards", standards are not ok and the
user is warned "Problem with standards! Redo measurement!".

3)  If R2 is greater than "Linearity of standards", concentration values are
calculated based on the linear regression parameters, copied to the "Concentration"-udf
on the output artifacts (one result file per sample). The "Conc. Units"-udf on the same
artifacts are set to "ng/ul".

4)  "End RFU" values from "Quant-iT Result File 1" are copied to the udf
"Fluorescence intentisy 1" of the input analyte to the process, and "End RFU" values from
"Quant-iT Result File 2" are copied to the udf "Fluorescence intensity 2".

Written by Maya Brandi
"""

import os
import sys
import logging
import numpy as np

from argparse import ArgumentParser
from requests import HTTPError
from genologics.lims import Lims
from genologics.config import BASEURI,USERNAME,PASSWORD
from genologics.entities import Process
from genologics.epp import EppLogger
from genologics.epp import set_field
from genologics.epp import ReadResultFiles
lims = Lims(BASEURI,USERNAME,PASSWORD)

class QunatiT():
    def __init__(self, process):
        self.file_handler = ReadResultFiles(process)
        self.udfs = dict(process.udf.items())
        self.abstract = []
        self.missing_udfs = []
        self.missing_samps =[]
        self.no_samps = 0
        self.standards = self._make_standards_dict()
        self.model = self._verify_standards()
        self.result_files = self._formated_result_files_dict()

    def _formated_result_files_dict(self):
        """"Quant-iT Result File 1" and "Quant-iT Result File 2" (the second is optional)
        uploaded by user, are formated and stored in a dict"""
        result_files_dict = {}
        file_names = {'Quant-iT Result File 1':'Fluorescence intensity 1',
                    'Quant-iT Result File 2':'Fluorescence intensity 2'}
        for f_name, udf_name in file_names.items():
            if self.file_handler.shared_files.has_key(f_name):
                result_file = self.file_handler.shared_files[f_name]
                result_files_dict[udf_name] = self.file_handler.format_file(result_file,
                                            name = f_name, root_key_col = 1, header_row = 19)
        return result_files_dict

    def _make_standards_dict(self):
        """End RFU standards are read from 'Standards File (.txt)' and stored in a dict"""
        standards_file = self.file_handler.shared_files['Standards File (.txt)']
        standards_file_formated = self.file_handler.format_file(standards_file,
                        name = 'Standards File (.txt)', root_key_col = 1, header_row = 19)
        standards_dict = {}
        for k,v in standards_file_formated.items():
            if set(['Sample','End RFU']).issubset(v) and v['Sample'].split()[0]=='Standard':
                standard = int(v['Sample'].split()[1])
                standards_dict[standard] = float(v['End RFU'])
        return standards_dict

    def _nuclear_acid_amount_in_standards(self):
        """Nuclear acid amount in standards is calculated as
        "Supposed concentrations of standards" * "Standard volume" / "Standard dilution"
        Supposed concentrations of standards are different between Quant-iT BR
        assays and Quant-iT HS assays."""
        requiered_udfs = set(['Standard volume','Assay type','Standard dilution'])
        supp_conc_stds = {'RNA BR':[0,5,10,20,40,60,80,100],
                          'DNA BR':[0,5,10,20,40,60,80,100],
                          'RNA':[0,0.5,1,2,4,6,8,10],
                          'DNA HS':[0,0.5,1,2,4,6,8,10]}
        if requiered_udfs.issubset(self.udfs.keys()):
            nuclear_acid_amount = np.ones(8)
            for standard in range(8):
                supp_conc_standard = supp_conc_stds[self.udfs['Assay type']][standard]
                nuclear_acid_amount[standard] = np.true_divide(supp_conc_standard *
                                    self.udfs['Standard volume'], self.udfs['Standard dilution'])
            return nuclear_acid_amount
        elif not requiered_udfs.issubset(self.missing_udfs):
            self.missing_udfs += requiered_udfs
        return None

    def _linear_regression(self, X,Y):
        """Perform linear regression with intersect forced to origin. And calculates
        Pearson correlation coefficient R2. """
        X = np.array(X)
        X_force_zero = X[:,np.newaxis]
        slope = np.linalg.lstsq(X_force_zero, Y)[0]

        A = np.array([ X, np.ones(len(X))])
        resid = np.linalg.lstsq(A.T,Y)[1]
        R2 = 1 - resid / (Y.size * Y.var())
        return float(R2), float(slope)

    def _verify_standards(self):
        """Performing linear regresion on standards.
        X = Relative fluorescence intensities of 8 standards
        Y = Nuclear acid amount in standards
        Y = slope*X + intersect; R2=Pearson correlation coefficient."""
        amount_in_standards = self._nuclear_acid_amount_in_standards()
        if amount_in_standards is not None:
            relative_standards = np.ones(8)
            for k,v in self.standards.items():
                relative_standards[k-1] = v - self.standards[1]
            R2, slope = self._linear_regression(relative_standards, amount_in_standards)
            return [R2, slope]
        else:
            return None

    def get_and_set_fluor_int(self, target_file):
        """Copies "End RFU" values from "Quant-iT Result File 1" and "Quant-iT Result File 2"
        (if provided) to udfs "Fluorescence intentisy 1" and "Fluorescence intensity 2.
        Calculates and returns Relative fluorescence intensitiy standards:
        rel_fluor_int = The End RFU of standards - Background fluorescence intensity"""
        sample = target_file.samples[0].name
        fluor_int = []
        target_udfs = dict(target_file.udf.items())
        if target_udfs.has_key("Fluorescence intentisy 1"): del target_file.udf["Fluorescence intentisy 1"]
        if target_udfs.has_key("Fluorescence intentisy 2"): del target_file.udf["Fluorescence intentisy 2"]
        for udf_name ,formated_file in self.result_files.items():
            if sample in formated_file.keys():
                fluor_int.append(int(formated_file[sample]['End RFU']))
                target_file.udf[udf_name] = int(formated_file[sample]['End RFU'])
            else:
                self.missing_samps.append(sample)
        set_field(target_file)
        rel_fluor_int = np.mean(fluor_int) - self.standards[1]
        return rel_fluor_int

    def calc_and_set_conc(self, target_file, rel_fluor_int):
        """Concentrations are calculated based on the linear regression parametersand copied to
        the "Concentration"-udf of the target_file. The "Conc. Units"-udf is set to "ng/ul"""
        requiered_udfs = set(['Sample volume','Standard dilution','WS volume'])
        if requiered_udfs.issubset(self.udfs.keys()) and self.model:
            conc = np.true_divide((self.model[1] * rel_fluor_int * (self.udfs['WS volume'] +
            self.udfs['Sample volume'])),self.udfs['Sample volume']*(self.udfs['WS volume'] +
                                                                self.udfs['Standard volume']))
            target_file.udf['Concentration'] = conc
            target_file.udf['Conc. Units'] = 'ng/ul'
            set_field(target_file)
            self.no_samps +=1
        elif not requiered_udfs.issubset(self.missing_udfs):
            self.missing_udfs += requiered_udfs

def main(lims, pid, epp_logger):
    process = Process(lims,id = pid)
    QiT = QunatiT(process)
    target_files = dict((r.samples[0].name, r) for r in process.result_files())
    if QiT.model and 'Linearity of standards' in QiT.udfs.keys():
        R2 = QiT.model[0]
        if R2 >= QiT.udfs['Linearity of standards']:
            QiT.abstract.insert(0,"R2 = {0}. Standards OK.".format(R2))
            if QiT.result_files:
                for sample, target_file in target_files.items():
                    rel_fluor_int = QiT.get_and_set_fluor_int(target_file)
                    QiT.calc_and_set_conc(target_file, rel_fluor_int)
                QiT.abstract.append("Concentrations uploaded for {0} samples.".format(QiT.no_samps))
            else:
                QiT.abstract.append("Upload input file(s) for samples.")
        else:
            QiT.abstract.insert(0, "R2 = {0}. Problem with standards! Redo measurement!".format(R2))
    else:
        QiT.missing_udfs.append('Linearity of standards')
    if QiT.missing_samps:
        QiT.abstract.append("The folowing samples are missing in Quant-iT result File 1 or 2: {0}.".format(
                                                                            ', '.join(QiT.missing_samps)))

    if QiT.missing_udfs:
        QiT.abstract.append("Are all of the folowing udfs set? : {0}".format(', '.join(QiT.missing_udfs)))

    print >> sys.stderr, ' '.join(QiT.abstract)

if __name__ == "__main__":
    parser = ArgumentParser(description=DESC)
    parser.add_argument('--pid', default = None , dest = 'pid',
                        help='Lims id for current Process')
    parser.add_argument('--log', dest = 'log',
                        help=('File name for standard log file, '
                              'for runtime information and problems.'))

    args = parser.parse_args()
    lims = Lims(BASEURI,USERNAME,PASSWORD)
    lims.check_version()

    with EppLogger(log_file=args.log, lims=lims, prepend=True) as epp_logger:
        main(lims, args.pid, epp_logger)

<|endoftext|>


<commit_before>import sublime, sublime_plugin
from datetime import datetime

class ItodoBase(sublime_plugin.TextCommand):
  def run(self, edit):
    filename = self.view.file_name()
    if filename is None or not filename.endswith('.todo'):
      return False
    self.runCommand(edit)

class NewCommand(ItodoBase):
  def runCommand(self, edit):
    for region in self.view.sel():
      line = self.view.line(region)
      line_contents = self.view.substr(line) + '\n- '
      self.view.replace(edit, line, line_contents)

class CompleteCommand(ItodoBase):
  def runCommand(self, edit):
    for region in self.view.sel():
      line = self.view.line(region)
      line_contents = self.view.substr(line).strip()
      # prepend @done if item is ongoing
      if line_contents.startswith('-'):
        self.view.insert(edit, line.end(), " @done (%s)" % datetime.now().strftime("%Y-%m-%d %H:%M"))
        self.view.replace(edit, self.view.word(line.begin()), "+ ")
      # undo @todo
      elif line_contents.startswith('+'):
        subfix = self.view.find('(\s)*@done(.)+\)$', line.begin())
        self.view.erase(edit, subfix)
        self.view.replace(edit, self.view.word(line.begin()), "- ")
      <commit_msg>case for adding new todo on an empty line<commit_after>import sublime, sublime_plugin
from datetime import datetime

class ItodoBase(sublime_plugin.TextCommand):
  def run(self, edit):
    filename = self.view.file_name()
    if filename is None or not filename.endswith('.todo'):
      return False
    self.runCommand(edit)

class NewCommand(ItodoBase):
  def runCommand(self, edit):
    for region in self.view.sel():
      line = self.view.line(region)
      # don't add a newline when creating new item with cursor is at an empty line
      if not line:
        line_contents = '- '
        self.view.insert(edit, line.begin(), line_contents)
      # add a newline when creating new item when cursor is at another line
      else:
        line_contents = self.view.substr(line) + '\n- '
        self.view.replace(edit, line, line_contents)

class CompleteCommand(ItodoBase):
  def runCommand(self, edit):
    for region in self.view.sel():
      line = self.view.line(region)
      line_contents = self.view.substr(line).strip()
      # prepend @done if item is ongoing
      if line_contents.startswith('-'):
        self.view.insert(edit, line.end(), " @done (%s)" % datetime.now().strftime("%Y-%m-%d %H:%M"))
        self.view.replace(edit, self.view.word(line.begin()), "+ ")
      # undo @todo
      elif line_contents.startswith('+'):
        subfix = self.view.find('(\s)*@done(.)+\)$', line.begin())
        self.view.erase(edit, subfix)
        self.view.replace(edit, self.view.word(line.begin()), "- ")
      <|endoftext|>


<commit_before>from _version import version as __version__

from api import parse
<commit_msg>python 3+ compatibility and adding test data path<commit_after>import os

from fcsparser._version import version as __version__
from fcsparser.api import parse

test_sample_path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
    'tests', 'data', 'FlowCytometers', 'HTS_BD_LSR-II', 'HTS_BD_LSR_II_Mixed_Specimen_001_D6_D06.fcs')

<|endoftext|>


<commit_before># Copyright (c) 2009, 2010, Dmitry Vasiliev <dima@hlabs.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#  * Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution.
#  * Neither the name of the copyright holders nor the names of its
#    contributors may be used to endorse or promote products derived from this
#    software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

"""Erlang port protocol."""

__author__ = "Dmitry Vasiliev <dima@hlabs.org>"

import os
import sys
import errno
import traceback
from struct import pack, unpack

from erlport.erlterms import Atom, encode, decode

class Protocol(object):
    """Erlang port protocol."""

    def run(self, port):
        """Run processing loop."""
        while True:
            try:
                message = port.read()
            except EOFError:
                break
            self.handle(port, message)

    def handle(self, port, message):
        """Handle incoming message."""
        if not (isinstance(message, Atom)
                or isinstance(message, tuple) and len(message) > 0):
            response = Atom("error"), Atom("badarg")
        else:
            if isinstance(message, Atom):
                name = message
                args = ()
            else:
                name = message[0]
                args = message[1:]
            if not isinstance(name, Atom):
                response = Atom("error"), Atom("badarg")
            else:
                handler = getattr(self, "handle_%s" % name, None)
                if handler is None:
                    response = Atom("error"), Atom("undef")
                else:
                    try:
                        response = handler(*args)
                    except:
                        response = self._handle_error(sys.exc_info())
        port.write(response)

    def _handle_error(self, exception):
        t, val, tb = exception
        exc = Atom("%s.%s" % (t.__module__, t.__name__))
        exc_tb = traceback.extract_tb(tb)
        exc_tb.reverse()
        return Atom("error"), (Atom("exception"), (exc, unicode(val), exc_tb))

class Port(object):
    """Erlang port."""

    _formats = {
        1: "B",
        2: ">H",
        4: ">I",
        }

    def __init__(self, packet=1, use_stdio=False, compressed=False,
            descriptors=None):
        self._format = self._formats.get(packet)
        if self._format is None:
            raise ValueError("invalid packet size value: %s" % packet)
        self.packet = packet
        self.compressed = compressed

        if descriptors is not None:
            self.in_d, self.out_d = descriptors
        elif use_stdio:
            self.in_d, self.out_d = 0, 1
        else:
            self.in_d, self.out_d = 3, 4

    def _read_data(self, length):
        data = ""
        while length > 0:
            try:
                buf = os.read(self.in_d, length)
            except IOError, why:
                if why.errno == errno.EPIPE:
                    raise EOFError()
                raise
            if not buf:
                raise EOFError()
            data += buf
            length -= len(buf)
        return data

    def read(self):
        """Read incoming message."""
        data = self._read_data(self.packet)
        length, = unpack(self._format, data)
        data = self._read_data(length)
        return decode(data)[0]

    def write(self, message):
        """Write outgoing message."""
        data = encode(message, compressed=self.compressed)
        data = pack(self._format, len(data)) + data
        while len(data) != 0:
            try:
                n = os.write(self.out_d, data)
            except IOError, why:
                if why.errno == errno.EPIPE:
                    raise EOFError()
                raise
            if n == 0:
                raise EOFError()
            data = data[n:]

    def close(self):
        """Close port."""
        os.close(self.in_d)
        os.close(self.out_d)
<commit_msg>It's OSError actually<commit_after># Copyright (c) 2009, 2010, Dmitry Vasiliev <dima@hlabs.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#  * Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution.
#  * Neither the name of the copyright holders nor the names of its
#    contributors may be used to endorse or promote products derived from this
#    software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

"""Erlang port protocol."""

__author__ = "Dmitry Vasiliev <dima@hlabs.org>"

import os
import sys
import errno
import traceback
from struct import pack, unpack

from erlport.erlterms import Atom, encode, decode

class Protocol(object):
    """Erlang port protocol."""

    def run(self, port):
        """Run processing loop."""
        while True:
            try:
                message = port.read()
            except EOFError:
                break
            self.handle(port, message)

    def handle(self, port, message):
        """Handle incoming message."""
        if not (isinstance(message, Atom)
                or isinstance(message, tuple) and len(message) > 0):
            response = Atom("error"), Atom("badarg")
        else:
            if isinstance(message, Atom):
                name = message
                args = ()
            else:
                name = message[0]
                args = message[1:]
            if not isinstance(name, Atom):
                response = Atom("error"), Atom("badarg")
            else:
                handler = getattr(self, "handle_%s" % name, None)
                if handler is None:
                    response = Atom("error"), Atom("undef")
                else:
                    try:
                        response = handler(*args)
                    except:
                        response = self._handle_error(sys.exc_info())
        port.write(response)

    def _handle_error(self, exception):
        t, val, tb = exception
        exc = Atom("%s.%s" % (t.__module__, t.__name__))
        exc_tb = traceback.extract_tb(tb)
        exc_tb.reverse()
        return Atom("error"), (Atom("exception"), (exc, unicode(val), exc_tb))

class Port(object):
    """Erlang port."""

    _formats = {
        1: "B",
        2: ">H",
        4: ">I",
        }

    def __init__(self, packet=1, use_stdio=False, compressed=False,
            descriptors=None):
        self._format = self._formats.get(packet)
        if self._format is None:
            raise ValueError("invalid packet size value: %s" % packet)
        self.packet = packet
        self.compressed = compressed

        if descriptors is not None:
            self.in_d, self.out_d = descriptors
        elif use_stdio:
            self.in_d, self.out_d = 0, 1
        else:
            self.in_d, self.out_d = 3, 4

    def _read_data(self, length):
        data = ""
        while length > 0:
            try:
                buf = os.read(self.in_d, length)
            except OSError, why:
                if why.errno == errno.EPIPE:
                    raise EOFError()
                raise
            if not buf:
                raise EOFError()
            data += buf
            length -= len(buf)
        return data

    def read(self):
        """Read incoming message."""
        data = self._read_data(self.packet)
        length, = unpack(self._format, data)
        data = self._read_data(length)
        return decode(data)[0]

    def write(self, message):
        """Write outgoing message."""
        data = encode(message, compressed=self.compressed)
        data = pack(self._format, len(data)) + data
        while len(data) != 0:
            try:
                n = os.write(self.out_d, data)
            except IOError, why:
                if why.errno == errno.EPIPE:
                    raise EOFError()
                raise
            if n == 0:
                raise EOFError()
            data = data[n:]

    def close(self):
        """Close port."""
        os.close(self.in_d)
        os.close(self.out_d)
<|endoftext|>


<commit_before>from django.test import TestCase
from django.test.client import Client
from django.core.urlresolvers import reverse
from django.conf import settings

from whats_fresh_api.models import *
from django.contrib.gis.db import models

import os
import time
import sys
import datetime
import json

class ProductViewTestCase(TestCase):
    fixtures = ['whats_fresh_api/tests/testdata/test_fixtures.json']
    def setup(self):
        self.expected_json = {
            "error": {
                "error_status": false,
                "error_name": null,
                "error_text": null,
                "error_level": null
            },
            "1": {
                "model": "whats_fresh_api.Product",
                "pk": "2",
                    "fields": {
                    "name": "Starfish Voyager",
                    "variety": "Tuna",
                    "alt_name": "The Stargazer",
                    "description": "This is one sweet fish!",
                    "origin": "The Delta Quadrant",
                    "season": "Season 1",
                    "available": "True",
                    "market_price": "$33.31",
                    "link": "http://www.amazon.com/Star-Trek-Voyager-Complete-Seventh/dp/B00062IDCO/",
                    "image_id": "1",
                    "story_id": "1",
                    "created": "2014-08-08 23:27:05.568395+00:00",
                    "modified": "2014-08-08 23:27:05.568395+00:00"
                }
            },
            "2": {
                "model": "whats_fresh_api.Product",
                "pk": "1",
                "fields": {
                    "name": "Ezri Dax",
                    "variety": "Freshwater Eel",
                    "alt_name": "Jadzia",
                    "description": "That's not actually an eel, it's a symbiote.",
                    "origin": "Trill",
                    "season": "Season 7",
                    "available": "True",
                    "market_price": "$32.64 per season",
                    "link": "http://www.amazon.com/Star-Trek-Deep-Space-Nine/dp/B00008KA57/",
                    "image_id": "1",
                    "story_id": "2",
                    "created": "2014-08-08 23:27:05.568395+00:00",
                    "modified": "2014-08-08 23:27:05.568395+00:00"
                }
            }
        }

    def test_url_endpoint(self):
        url = reverse('products-list')
        self.assertEqual(url, '/products')

    def test_json_equals(self):
        c = Client()
        response = c.get(reverse('products-list')).content
        parsed_answer = json.loads(response)
        expected_answer = json.loads(self.expected_json)
        self.assertTrue(parsed_answer == expected_answer)
<commit_msg>Changed true/false from strings to native types.<commit_after>from django.test import TestCase
from django.test.client import Client
from django.core.urlresolvers import reverse
from django.conf import settings

from whats_fresh_api.models import *
from django.contrib.gis.db import models

import os
import time
import sys
import datetime
import json

class ProductViewTestCase(TestCase):
    fixtures = ['whats_fresh_api/tests/testdata/test_fixtures.json']
    def setup(self):
        self.expected_json = {
            "error": {
                "error_status": false,
                "error_name": null,
                "error_text": null,
                "error_level": null
            },
            "1": {
                "model": "whats_fresh_api.Product",
                "pk": "2",
                    "fields": {
                    "name": "Starfish Voyager",
                    "variety": "Tuna",
                    "alt_name": "The Stargazer",
                    "description": "This is one sweet fish!",
                    "origin": "The Delta Quadrant",
                    "season": "Season 1",
                    "available": True,
                    "market_price": "$33.31",
                    "link": "http://www.amazon.com/Star-Trek-Voyager-Complete-Seventh/dp/B00062IDCO/",
                    "image_id": "1",
                    "story_id": "1",
                    "created": "2014-08-08 23:27:05.568395+00:00",
                    "modified": "2014-08-08 23:27:05.568395+00:00"
                }
            },
            "2": {
                "model": "whats_fresh_api.Product",
                "pk": "1",
                "fields": {
                    "name": "Ezri Dax",
                    "variety": "Freshwater Eel",
                    "alt_name": "Jadzia",
                    "description": "That's not actually an eel, it's a symbiote.",
                    "origin": "Trill",
                    "season": "Season 7",
                    "available": True,
                    "market_price": "$32.64 per season",
                    "link": "http://www.amazon.com/Star-Trek-Deep-Space-Nine/dp/B00008KA57/",
                    "image_id": "1",
                    "story_id": "2",
                    "created": "2014-08-08 23:27:05.568395+00:00",
                    "modified": "2014-08-08 23:27:05.568395+00:00"
                }
            }
        }

    def test_url_endpoint(self):
        url = reverse('products-list')
        self.assertEqual(url, '/products')

    def test_json_equals(self):
        c = Client()
        response = c.get(reverse('products-list')).content
        parsed_answer = json.loads(response)
        expected_answer = json.loads(self.expected_json)
        self.assertTrue(parsed_answer == expected_answer)
<|endoftext|>


<commit_before>import tpdp
import roll_history
import logbook

debug_enabled = True

def debug_print(*args):
    if debug_enabled:
        for arg in args:
            print arg
    return

def missing_stub(msg):
    print msg
    return 0

#attacker.allegiance_shared(tgt) is not working
def floatFriendlyFire(attacker, tgt):
    if attacker.allegiance_shared(tgt) and (tgt in game.party) == (attacker in game.party):
        debug_print("Debug: Friendly Fire triggered")
        tgt.float_mesfile_line('mes\\combat.mes', 107) # Friendly Fire
    else:
        debug_print("Debug: Friendly Fire NOT triggered", "Debug attacker.allegiance_shared(tgt): {}".format(attacker.allegiance_shared(tgt)), "Debug tgt in game.party: {}".format(tgt in game.party), "Debug attacker in game.party: {}".format(attacker in game.party))
    return

def getUsedWeapon(flags, attacker):
    unarmed = OBJ_HANDLE_NULL
    if flags & D20CAF_TOUCH_ATTACK:
        return unarmed
    elif flags & D20CAF_SECONDARY_WEAPON:
        offhandItem = attacker.item_worn_at(item_wear_weapon_secondary)
        if offhandItem.type == obj_t_weapon:
            return offhandItem
    else:
        mainhandItem = attacker.item_worn_at(item_wear_weapon_primary)
        if mainhandItem.type == obj_t_weapon:
            return mainhandItem
    return unarmed

def playSoundEffect(weaponUsed, attacker, tgt, sound_event):
    sound_id = attacker.soundmap_item(weaponUsed, tgt, sound_event)
    game.sound_local_obj(sound_id, attacker)
    return

def deal_attack_damage(attacker, tgt, d20_data, flags, action_type):
    # return value is used by Coup De Grace

    #Provoke Hostility
    attacker.attack(tgt, 1, 0)

    #Check if target is alive
    if tgt == OBJ_HANDLE_NULL or tgt.is_dead_or_destroyed():
        return -1

    #Create evt_obj_dam
    evt_obj_dam = tpdp.EventObjDamage()
    evt_obj_dam.attack_packet.action_type = tpdp.D20ActionType(action_type)
    evt_obj_dam.attack_packet.attacker = attacker
    evt_obj_dam.attack_packet.target = tgt
    evt_obj_dam.attack_packet.event_key = d20_data
    evt_obj_dam.attack_packet.set_flags(flags)

    #Set weapon used
    usedWeapon = getUsedWeapon(evt_obj_dam.attack_packet.get_flags(), attacker)
    evt_obj_dam.attack_packet.set_weapon_used(usedWeapon)

    #Check ammo
    evt_obj_dam.attack_packet.ammo_item = attacker.get_ammo_used()

    #Check Concealment Miss
    # is this actually set anywhere? check!
    if flags & D20CAF_CONCEALMENT_MISS:
        roll_history.add_from_pattern(11, attacker, tgt)
        attacker.float_mesfile_line('mes\\combat.mes', 45) # Miss (Concealment)
        playSoundEffect(evt_obj_dam.attack_packet.get_weapon_used(), attacker, tgt, 6)
        evt_obj_dam.send_signal(attacker, S_Attack_Made)
        return -1

    #Check normal Miss
    if (flags & D20CAF_HIT) == 0:
        attacker.float_mesfile_line('mes\\combat.mes', 29) # Miss
        evt_obj_dam.send_signal(attacker, S_Attack_Made)
        playSoundEffect(evt_obj_dam.attack_packet.get_weapon_used(), attacker, tgt, 6)
        #Check if arrow was deflected
        if flags & D20CAF_DEFLECT_ARROWS:
            tgt.float_mesfile_line('mes\\combat.mes', 5052) #{5052}{Deflect Arrows}
            roll_history.add_from_pattern(12, attacker, tgt)
        #dodge animation
        if tgt.is_unconscious() or tgt.d20_query(Q_Prone):
            return -1
        else:
            tgt.anim_goal_push_dodge(attacker)
        return -1

    #Check if Friendly Fire and trigger float if true
    floatFriendlyFire(attacker, tgt)

    #Check if is already unconscious
    wasAlreadyUnconscious = tgt.is_unconscious()

    #dispatch damage
    evt_obj_dam.dispatch(attacker, ET_OnDealingDamage, EK_NONE)

    #handle critical hit
    if evt_obj_dam.attack_packet.get_flags() & D20CAF_CRITICAL:
        #create evt_obj_crit_dice
        evt_obj_crit_dice = tpdp.EventObjAttack()
        evt_obj_crit_dice.attack_packet.action_type = tpdp.D20ActionType(action_type)
        evt_obj_crit_dice.attack_packet.attacker = attacker
        evt_obj_crit_dice.attack_packet.target = tgt
        evt_obj_crit_dice.attack_packet.event_key = d20_data
        evt_obj_crit_dice.attack_packet.set_flags(evt_obj_dam.attack_packet.get_flags())
        evt_obj_crit_dice.attack_packet.set_weapon_used(evt_obj_dam.attack_packet.get_weapon_used())
        #Check ammo
        evt_obj_crit_dice.attack_packet.ammo_item = attacker.get_ammo_used()
        #apply extra damage
        extraDamageDice = evt_obj_crit_dice.dispatch(attacker, OBJ_HANDLE_NULL, ET_OnGetCriticalHitExtraDice, EK_NONE)
        debug_print("Debug extraDamageDice: {}".format(extraDamageDice))

        evt_obj_dam.damage_packet.critical_multiplier_apply(extraDamageDice + 1)
        attacker.float_mesfile_line('mes\\combat.mes', 12) #{12}{Critical Hit!}
        #play crit hit sound
        soundIdTarget = tgt.soundmap_critter(0)
        game.sound_local_obj(soundIdTarget, tgt)
        playSoundEffect(evt_obj_crit_dice.attack_packet.get_weapon_used(), attacker, tgt, 7)
        #Logbook increase crit count
        logbook.inc_criticals(attacker)
    else:
        #if no crit only play sound
        playSoundEffect(evt_obj_dam.attack_packet.get_weapon_used(), attacker, tgt, 5)

    #Logbook
    logbook.is_weapon_damage = 1 # used for recording attack damage

    #Call damage_critter
    damage_critter(attacker, tgt, evt_obj_dam)

    #Play damage particle effects
    evt_obj_dam.damage_packet.play_pfx(tgt)

    #Send signals
    evt_obj_dam.send_signal(attacker, S_Attack_Made)
    if not wasAlreadyUnconscious and tgt.is_unconscious():
        evt_obj_dam.send_signal(attacker, S_Dropped_Enemy)

    debug_print("Debug: print overall damage: {}".format(evt_obj_dam.damage_packet.get_overall_damage()))
    overall_dam = evt_obj_dam.damage_packet.get_overall_damage()
    return overall_dam

def deal_spell_damage(tgt, attacker, dice, damageType, attackPower, reduction, damageDescId, action_type, spellId, flags):
    spellPacket = tpdp.spellPacket(spellId)
    if not tgt:
        return

    #Check if Friendly Fire and trigger float if true
    floatFriendlyFire(attacker, tgt)

    #Provoke Hostility
    #missing_stub("aiSys.ProvokeHostility(attacker, tgt, 1, 0);")
    attacker.attack(tgt, 1, 0)

    #Check if target is alive
    if tgt == OBJ_HANDLE_NULL or tgt.is_dead_or_destroyed():
        return

    #create evt_obj_dam
    evt_obj_dam = tpdp.EventObjDamage()
    missing_stub("evt_obj_dam.attack_packet.action_type = action_type #this returns an error")
    evt_obj_dam.attack_packet.attacker = attacker
    evt_obj_dam.attack_packet.target = tgt
    evt_obj_dam.attack_packet.event_key = 1 #Took this from the c++ code, not sure if a hard number is good
    evt_obj_dam.attack_packet.set_flags(flags)

    #Set weapon used
    if attacker.is_critter():
        usedWeapon = getUsedWeapon(evt_obj_dam.attack_packet.get_flags(), attacker)
        evt_obj_dam.attack_packet.set_weapon_used(usedWeapon)
        #Check ammo
        evt_obj_dam.attack_packet.ammo_item = attacker.get_ammo_used()
    else:
        evt_obj_dam.attack_packet.set_weapon_used(OBJ_HANDLE_NULL)
        evt_obj_dam.attack_packet.ammo_item = OBJ_HANDLE_NULL

    #Add damage mod factor
    if reduction != 100:
        #addresses.AddDamageModFactor(&evtObjDam.damage,  reduction * 0.01f, type, damageDescId);
        evt_obj_dam.damage_packet.add_mod_factor((reduction * 0.01), damageType, damageDescId)

    #Add damage dice
    #If we could get a string support for add_dice
    #we could get rid of this ugly ID 103 in damage.mes
    #ID 103 = Unknown
    #Could be replaced by:
    #spellEnum = tpdp.SpellPacket(spellId).spell_enum
    #spellName = game.get_spell_mesline(spellEnum)
    #spellNameTag = spellName.upper().replace(" ", "_")
    #evt_obj_dam.damage_packet.add_dice_with_custom_string(dice, damageType, "~{}~[TAG_SPELLS_{}]".format(spellName, spellNameTag))
    evt_obj_dam.damage_packet.add_dice(dice, damageType, 103)

    #Add attackPower
    evt_obj_dam.damage_packet.attack_power(attackPower)

    #set MetaMagic
    metaMagicData = spellPacket.get_metamagic_data()
    if missing_stub("if (mmData.metaMagicEmpowerSpellCount)"):
        missing_stub("evtObjDam.damage.flags |= 2; // empowered")
    if missing_stub("if (mmData.metaMagicFlags & 1)"):
        missing_stub("evtObjDam.damage.flags |= 1; // maximized")

    #Dispatch damage
    evt_obj_dam.damage_packet.dispatch_spell_damage(attacker, tgt, spellPacket)

    #Logbook
    logbook.is_weapon_damage = 0 # used for recording attack damage

    #Call Damage Critter
    damage_critter(attacker, tgt, evt_obj_dam)

    return

def checkAnimationSkip(tgt):
    if tgt.is_unconscious() or tgt.d20_query(Q_Prone):
        return True
    return False

def float_hp_damage(attacker, tgt, damTot, subdualDamTot):

    leaderOfAttacker = attacker.leader_get()
    if leaderOfAttacker in game.party:
        floatColor = tf_yellow
    elif attacker.type == obj_t_pc:
        floatColor = tf_white
    else:
        floatColor = tf_red

    if damTot != 0 and subdualDamTot != 0:
        combatMesLine = game.get_mesline("mes/combat.mes", 1) # HP
        tgt.float_text_line("{} {}".format(damTot, combatMesLine), floatColor)
        combatMesLine = game.get_mesline("mes/combat.mes", 25) # Nonlethal
        tgt.float_text_line("{} {}".format(subdualDamTot, combatMesLine), floatColor)
    elif subdualDamTot !=0: # damTot ==0
        combatMesLine = game.get_mesline("mes/combat.mes", 25) # Nonlethal
        tgt.float_text_line("{} {}".format(subdualDamTot, combatMesLine), floatColor)
    #if attack deals 0 damage to due damage reduction/resistance
    else: # subdualDamTot ==0; damTot can be 0 or not
        combatMesLine = game.get_mesline("mes/combat.mes", 1) # HP
        tgt.float_text_line("{} {}".format(damTot, combatMesLine), floatColor)
    return

def damage_critter(attacker, tgt, evt_obj_dam):
    if not tgt:
        return

    #skipHitAnim
    skipHitAnim = checkAnimationSkip(tgt)

    #Check Invulnerability
    tgtFlags = tgt.object_flags_get()
    if tgtFlags & OF_INVULNERABLE:
        evt_obj_dam.damage_packet.add_mod_factor(0.0, D20DT_UNSPECIFIED, 104)

    #Dispatch Damage
    evt_obj_dam.damage_packet.calc_final_damage()
    evt_obj_dam.dispatch(tgt, ET_OnTakingDamage, EK_NONE)
    if evt_obj_dam.attack_packet.get_flags() & D20CAF_TRAP:
        attacker = OBJ_HANDLE_NULL
    elif attacker != OBJ_HANDLE_NULL:
        evt_obj_dam.dispatch(attacker, ET_OnDealingDamage2, EK_NONE)
    evt_obj_dam.dispatch(tgt, ET_OnTakingDamage2, EK_NONE)

    #Set last hit by
    if attacker != OBJ_HANDLE_NULL:
        tgt.obj_set_obj(obj_f_last_hit_by, attacker)

    #Assign damage
    damTot = max(evt_obj_dam.damage_packet.get_overall_damage(), 0)
    hpDam = tgt.obj_get_int(obj_f_hp_damage)
    hpDam += damTot
    tgt.set_hp_damage(hpDam)

    #History Roll Window
    history_roll_id = roll_history.add_damage_roll(attacker, tgt, evt_obj_dam.damage_packet)
    game.create_history_from_id(history_roll_id)

    #Send Signal HP_Changed
    tgt.d20_send_signal(S_HP_Changed, -damTot, -1 if damTot > 0 else 0)

    #Triggers for dealing damage
    if damTot:
        #Add Damaged condition
        tgt.condition_add("Damaged", damTot)
        if attacker and tgt:
            #Log Highest Damage Record
            isWeaponDamage = logbook.is_weapon_damage
            logbook.record_highest_damage(isWeaponDamage, damTot, attacker, tgt)
            #Check for friendly fire
            if attacker != tgt and attacker.is_friendly(tgt):
                tgt.sound_play_friendly_fire(attacker)

    #Subdual Damage
    subdualDamTot = evt_obj_dam.damage_packet.get_overall_damage_by_type(D20DT_SUBDUAL)
    if subdualDamTot > 0 and tgt != OBJ_HANDLE_NULL:
        tgt.condition_add("Damaged", subdualDamTot)
    subdual_dam = tgt.obj_get_int(obj_f_critter_subdual_damage)
    tgt.set_subdual_damage(subdual_dam + subdualDamTot)
    tgt.d20_send_signal(S_HP_Changed, subdualDamTot, -1 if subdualDamTot > 0 else 0)

    #Create Floatline
    float_hp_damage(attacker, tgt, damTot, subdualDamTot)

    #Push hit Animation
    if attacker:
        if not skipHitAnim:
            tgt.anim_goal_push_hit_by_weapon(attacker)
    return<commit_msg>Fixed deal_spell_damage errors<commit_after>import tpdp
import roll_history
import logbook

debug_enabled = True

def debug_print(*args):
    if debug_enabled:
        for arg in args:
            print arg
    return

def missing_stub(msg):
    print msg
    return 0

#attacker.allegiance_shared(tgt) is not working
def floatFriendlyFire(attacker, tgt):
    if attacker.allegiance_shared(tgt) and (tgt in game.party) == (attacker in game.party):
        debug_print("Debug: Friendly Fire triggered")
        tgt.float_mesfile_line('mes\\combat.mes', 107) # Friendly Fire
    else:
        debug_print("Debug: Friendly Fire NOT triggered", "Debug attacker.allegiance_shared(tgt): {}".format(attacker.allegiance_shared(tgt)), "Debug tgt in game.party: {}".format(tgt in game.party), "Debug attacker in game.party: {}".format(attacker in game.party))
    return

def getUsedWeapon(flags, attacker):
    unarmed = OBJ_HANDLE_NULL
    if flags & D20CAF_TOUCH_ATTACK:
        return unarmed
    elif flags & D20CAF_SECONDARY_WEAPON:
        offhandItem = attacker.item_worn_at(item_wear_weapon_secondary)
        if offhandItem.type == obj_t_weapon:
            return offhandItem
    else:
        mainhandItem = attacker.item_worn_at(item_wear_weapon_primary)
        if mainhandItem.type == obj_t_weapon:
            return mainhandItem
    return unarmed

def playSoundEffect(weaponUsed, attacker, tgt, sound_event):
    sound_id = attacker.soundmap_item(weaponUsed, tgt, sound_event)
    game.sound_local_obj(sound_id, attacker)
    return

def deal_attack_damage(attacker, tgt, d20_data, flags, action_type):
    # return value is used by Coup De Grace

    #Provoke Hostility
    attacker.attack(tgt, 1, 0)

    #Check if target is alive
    if tgt == OBJ_HANDLE_NULL or tgt.is_dead_or_destroyed():
        return -1

    #Create evt_obj_dam
    evt_obj_dam = tpdp.EventObjDamage()
    evt_obj_dam.attack_packet.action_type = tpdp.D20ActionType(action_type)
    evt_obj_dam.attack_packet.attacker = attacker
    evt_obj_dam.attack_packet.target = tgt
    evt_obj_dam.attack_packet.event_key = d20_data
    evt_obj_dam.attack_packet.set_flags(flags)

    #Set weapon used
    usedWeapon = getUsedWeapon(evt_obj_dam.attack_packet.get_flags(), attacker)
    evt_obj_dam.attack_packet.set_weapon_used(usedWeapon)

    #Check ammo
    evt_obj_dam.attack_packet.ammo_item = attacker.get_ammo_used()

    #Check Concealment Miss
    # is this actually set anywhere? check!
    if flags & D20CAF_CONCEALMENT_MISS:
        roll_history.add_from_pattern(11, attacker, tgt)
        attacker.float_mesfile_line('mes\\combat.mes', 45) # Miss (Concealment)
        playSoundEffect(evt_obj_dam.attack_packet.get_weapon_used(), attacker, tgt, 6)
        evt_obj_dam.send_signal(attacker, S_Attack_Made)
        return -1

    #Check normal Miss
    if (flags & D20CAF_HIT) == 0:
        attacker.float_mesfile_line('mes\\combat.mes', 29) # Miss
        evt_obj_dam.send_signal(attacker, S_Attack_Made)
        playSoundEffect(evt_obj_dam.attack_packet.get_weapon_used(), attacker, tgt, 6)
        #Check if arrow was deflected
        if flags & D20CAF_DEFLECT_ARROWS:
            tgt.float_mesfile_line('mes\\combat.mes', 5052) #{5052}{Deflect Arrows}
            roll_history.add_from_pattern(12, attacker, tgt)
        #dodge animation
        if tgt.is_unconscious() or tgt.d20_query(Q_Prone):
            return -1
        else:
            tgt.anim_goal_push_dodge(attacker)
        return -1

    #Check if Friendly Fire and trigger float if true
    floatFriendlyFire(attacker, tgt)

    #Check if is already unconscious
    wasAlreadyUnconscious = tgt.is_unconscious()

    #dispatch damage
    evt_obj_dam.dispatch(attacker, ET_OnDealingDamage, EK_NONE)

    #handle critical hit
    if evt_obj_dam.attack_packet.get_flags() & D20CAF_CRITICAL:
        #create evt_obj_crit_dice
        evt_obj_crit_dice = tpdp.EventObjAttack()
        evt_obj_crit_dice.attack_packet.action_type = tpdp.D20ActionType(action_type)
        evt_obj_crit_dice.attack_packet.attacker = attacker
        evt_obj_crit_dice.attack_packet.target = tgt
        evt_obj_crit_dice.attack_packet.event_key = d20_data
        evt_obj_crit_dice.attack_packet.set_flags(evt_obj_dam.attack_packet.get_flags())
        evt_obj_crit_dice.attack_packet.set_weapon_used(evt_obj_dam.attack_packet.get_weapon_used())
        #Check ammo
        evt_obj_crit_dice.attack_packet.ammo_item = attacker.get_ammo_used()
        #apply extra damage
        extraDamageDice = evt_obj_crit_dice.dispatch(attacker, OBJ_HANDLE_NULL, ET_OnGetCriticalHitExtraDice, EK_NONE)
        debug_print("Debug extraDamageDice: {}".format(extraDamageDice))

        evt_obj_dam.damage_packet.critical_multiplier_apply(extraDamageDice + 1)
        attacker.float_mesfile_line('mes\\combat.mes', 12) #{12}{Critical Hit!}
        #play crit hit sound
        soundIdTarget = tgt.soundmap_critter(0)
        game.sound_local_obj(soundIdTarget, tgt)
        playSoundEffect(evt_obj_crit_dice.attack_packet.get_weapon_used(), attacker, tgt, 7)
        #Logbook increase crit count
        logbook.inc_criticals(attacker)
    else:
        #if no crit only play sound
        playSoundEffect(evt_obj_dam.attack_packet.get_weapon_used(), attacker, tgt, 5)

    #Logbook
    logbook.is_weapon_damage = 1 # used for recording attack damage

    #Call damage_critter
    damage_critter(attacker, tgt, evt_obj_dam)

    #Play damage particle effects
    evt_obj_dam.damage_packet.play_pfx(tgt)

    #Send signals
    evt_obj_dam.send_signal(attacker, S_Attack_Made)
    if not wasAlreadyUnconscious and tgt.is_unconscious():
        evt_obj_dam.send_signal(attacker, S_Dropped_Enemy)

    debug_print("Debug: print overall damage: {}".format(evt_obj_dam.damage_packet.get_overall_damage()))
    overall_dam = evt_obj_dam.damage_packet.get_overall_damage()
    return overall_dam

def deal_spell_damage(tgt, attacker, dice, damageType, attackPower, reduction, damageDescId, action_type, spellId, flags):
    debug_print("Debug Hook deal_spell_damage")
    debug_print("Debug spell target: {}".format(tgt), "Debug spell caster: {}".format(attacker), "Debug Dice: {}".format(dice), "Debug damageType: {}".format(damageType), "Debug attackPower: {}".format(attackPower), "Debug reduction: {}".format(reduction), "Debug damageDescId: {}".format(damageDescId), "Debug action_type: {}".format(action_type), "Debug spellId: {}".format(spellId), "Debug flags: {}".format(flags))
    spellPacket = tpdp.SpellPacket(spellId)
    if not tgt:
        debug_print("Debug No Target!")
        return

    #Check if Friendly Fire and trigger float if true
    floatFriendlyFire(attacker, tgt)

    #Provoke Hostility
    #missing_stub("aiSys.ProvokeHostility(attacker, tgt, 1, 0);")
    attacker.attack(tgt, 1, 0)

    #Check if target is alive
    if tgt == OBJ_HANDLE_NULL or tgt.is_dead_or_destroyed():
        debug_print("Debug target destroyed!")
        return

    #create evt_obj_dam
    evt_obj_dam = tpdp.EventObjDamage()
    evt_obj_dam.attack_packet.action_type = tpdp.D20ActionType(action_type)
    evt_obj_dam.attack_packet.attacker = attacker
    evt_obj_dam.attack_packet.target = tgt
    evt_obj_dam.attack_packet.event_key = 1 #Took this from the c++ code, not sure if a hard number is good
    evt_obj_dam.attack_packet.set_flags(flags)

    #Set weapon used
    if attacker.is_critter():
        usedWeapon = getUsedWeapon(evt_obj_dam.attack_packet.get_flags(), attacker)
        evt_obj_dam.attack_packet.set_weapon_used(usedWeapon)
        #Check ammo
        evt_obj_dam.attack_packet.ammo_item = attacker.get_ammo_used()
    else:
        evt_obj_dam.attack_packet.set_weapon_used(OBJ_HANDLE_NULL)
        evt_obj_dam.attack_packet.ammo_item = OBJ_HANDLE_NULL

    #Add damage mod factor
    if reduction != 100:
        #addresses.AddDamageModFactor(&evtObjDam.damage,  reduction * 0.01f, type, damageDescId);
        evt_obj_dam.damage_packet.add_mod_factor((reduction * 0.01), damageType, damageDescId)

    #Add damage dice
    #If we could get a string support for add_dice
    #we could get rid of this ugly ID 103 in damage.mes
    #ID 103 = Unknown
    #Could be replaced by:
    #spellEnum = tpdp.SpellPacket(spellId).spell_enum
    #spellName = game.get_spell_mesline(spellEnum)
    #spellNameTag = spellName.upper().replace(" ", "_")
    #evt_obj_dam.damage_packet.add_dice_with_custom_string(dice, damageType, "~{}~[TAG_SPELLS_{}]".format(spellName, spellNameTag))
    evt_obj_dam.damage_packet.add_dice(dice, damageType, 103)

    #Add attackPower
    evt_obj_dam.damage_packet.attack_power |= attackPower

    #set MetaMagic
    metaMagicData = spellPacket.get_metamagic_data()
    if missing_stub("if (mmData.metaMagicEmpowerSpellCount)"):
        missing_stub("evtObjDam.damage.flags |= 2; // empowered")
    if missing_stub("if (mmData.metaMagicFlags & 1)"):
        missing_stub("evtObjDam.damage.flags |= 1; // maximized")

    #Dispatch damage
    overall_dam = evt_obj_dam.dispatch_spell_damage(attacker, tgt, spellPacket)
    debug_print("Debug spell overall_dam: {}".format(overall_dam))

    #Logbook
    logbook.is_weapon_damage = 0 # used for recording attack damage

    #Call Damage Critter
    damage_critter(attacker, tgt, evt_obj_dam)

    return

def checkAnimationSkip(tgt):
    if tgt.is_unconscious() or tgt.d20_query(Q_Prone):
        return True
    return False

def float_hp_damage(attacker, tgt, damTot, subdualDamTot):

    leaderOfAttacker = attacker.leader_get()
    if leaderOfAttacker in game.party:
        floatColor = tf_yellow
    elif attacker.type == obj_t_pc:
        floatColor = tf_white
    else:
        floatColor = tf_red

    if damTot != 0 and subdualDamTot != 0:
        combatMesLine = game.get_mesline("mes/combat.mes", 1) # HP
        tgt.float_text_line("{} {}".format(damTot, combatMesLine), floatColor)
        combatMesLine = game.get_mesline("mes/combat.mes", 25) # Nonlethal
        tgt.float_text_line("{} {}".format(subdualDamTot, combatMesLine), floatColor)
    elif subdualDamTot !=0: # damTot ==0
        combatMesLine = game.get_mesline("mes/combat.mes", 25) # Nonlethal
        tgt.float_text_line("{} {}".format(subdualDamTot, combatMesLine), floatColor)
    #if attack deals 0 damage to due damage reduction/resistance
    else: # subdualDamTot ==0; damTot can be 0 or not
        combatMesLine = game.get_mesline("mes/combat.mes", 1) # HP
        tgt.float_text_line("{} {}".format(damTot, combatMesLine), floatColor)
    return

def damage_critter(attacker, tgt, evt_obj_dam):
    if not tgt:
        return

    #skipHitAnim
    skipHitAnim = checkAnimationSkip(tgt)

    #Check Invulnerability
    tgtFlags = tgt.object_flags_get()
    if tgtFlags & OF_INVULNERABLE:
        evt_obj_dam.damage_packet.add_mod_factor(0.0, D20DT_UNSPECIFIED, 104)

    #Dispatch Damage
    evt_obj_dam.damage_packet.calc_final_damage()
    evt_obj_dam.dispatch(tgt, ET_OnTakingDamage, EK_NONE)
    if evt_obj_dam.attack_packet.get_flags() & D20CAF_TRAP:
        attacker = OBJ_HANDLE_NULL
    elif attacker != OBJ_HANDLE_NULL:
        evt_obj_dam.dispatch(attacker, ET_OnDealingDamage2, EK_NONE)
    evt_obj_dam.dispatch(tgt, ET_OnTakingDamage2, EK_NONE)

    #Set last hit by
    if attacker != OBJ_HANDLE_NULL:
        tgt.obj_set_obj(obj_f_last_hit_by, attacker)

    #Assign damage
    damTot = max(evt_obj_dam.damage_packet.get_overall_damage(), 0)
    hpDam = tgt.obj_get_int(obj_f_hp_damage)
    hpDam += damTot
    tgt.set_hp_damage(hpDam)

    #History Roll Window
    history_roll_id = roll_history.add_damage_roll(attacker, tgt, evt_obj_dam.damage_packet)
    game.create_history_from_id(history_roll_id)

    #Send Signal HP_Changed
    tgt.d20_send_signal(S_HP_Changed, -damTot, -1 if damTot > 0 else 0)

    #Triggers for dealing damage
    if damTot:
        #Add Damaged condition
        tgt.condition_add("Damaged", damTot)
        if attacker and tgt:
            #Log Highest Damage Record
            isWeaponDamage = logbook.is_weapon_damage
            logbook.record_highest_damage(isWeaponDamage, damTot, attacker, tgt)
            #Check for friendly fire
            if attacker != tgt and attacker.is_friendly(tgt):
                tgt.sound_play_friendly_fire(attacker)

    #Subdual Damage
    subdualDamTot = evt_obj_dam.damage_packet.get_overall_damage_by_type(D20DT_SUBDUAL)
    if subdualDamTot > 0 and tgt != OBJ_HANDLE_NULL:
        tgt.condition_add("Damaged", subdualDamTot)
    subdual_dam = tgt.obj_get_int(obj_f_critter_subdual_damage)
    tgt.set_subdual_damage(subdual_dam + subdualDamTot)
    tgt.d20_send_signal(S_HP_Changed, subdualDamTot, -1 if subdualDamTot > 0 else 0)

    #Create Floatline
    float_hp_damage(attacker, tgt, damTot, subdualDamTot)

    #Push hit Animation
    if attacker:
        if not skipHitAnim:
            tgt.anim_goal_push_hit_by_weapon(attacker)
    return<|endoftext|>


<commit_before># -*- coding: utf-8; -*-
#
# This file is part of Superdesk.
#
# Copyright 2013, 2014 Sourcefabric z.u. and contributors.
#
# For the full copyright and license information, please see the
# AUTHORS and LICENSE files distributed with this source code, or
# at https://www.sourcefabric.org/superdesk/license
import superdesk
from superdesk.resource import Resource
from superdesk.services import BaseService
from superdesk import get_resource_service
from flask import render_template, json, request, current_app as app
import os
import io
import magic
from superdesk.celery_app import celery
from eve.io.mongo import MongoJSONEncoder
import logging

logger = logging.getLogger('superdesk')
BLOGSLIST_DIRECTORY = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir, 'blogslist'))
BLOGSLIST_ASSETS_DIR = 'blogslist_assets'
CONTENT_TYPES = {
    '.css': 'text/css',
    '.js': 'application/javascript',
    '.json': 'application/json'
}

bp = superdesk.Blueprint('embed_blogslist', __name__, template_folder='templates')
bloglist_assets_blueprint = superdesk.Blueprint('blogslist_assets', __name__, static_folder=BLOGSLIST_ASSETS_DIR)

def bloglist_assets():
    return {
            'scripts': [
                'vendors/moment/min/moment-with-locales.min.js',
                'vendors/angular/angular.min.js',
                'vendors/angular-resource/angular-resource.min.js',
                'vendors/angular-route/angular-route.min.js',
                'vendors/angular-gettext/dist/angular-gettext.min.js',
                # 'templates.js',
                'main.js'
            ],
            'styles': [
                'styles/embed.css',
                'styles/reset.css'
            ],
            # 'template': ['template.html'],
            'version': 'bower.json'
        }

def get_file_path():
    return os.path.join(BLOGSLIST_ASSETS_DIR, 'index.html')

@celery.task(soft_time_limit=1800)
def publish_assets(asset_type):
    assets = bloglist_assets()
    # version_path = os.path.join(BLOGSLIST_DIRECTORY, BLOGSLIST_ASSETS_DIR, assets['version'])
    # # loads version json from file
    # version = json.loads(open(version_path, 'rb').read()).get('version', '0.0.0')
    # Save the file in the media storage if needed
    for name in (assets[asset_type]):
        asset_file = os.path.join(BLOGSLIST_DIRECTORY, BLOGSLIST_ASSETS_DIR, name)
        with open(asset_file, 'rb') as file:
            # set the content type
            mime = magic.Magic(mime=True)
            content_type = mime.from_file(asset_file)
            if content_type == 'text/plain' and name.endswith(tuple(CONTENT_TYPES.keys())):
                content_type = CONTENT_TYPES[os.path.splitext(name)[1]]
            final_file_name = os.path.join(BLOGSLIST_ASSETS_DIR, name)
            # remove existing first
            app.media.delete(app.media.media_id(final_file_name,
                                                content_type=content_type,
                                                # version=version
                                                ))
            # upload
            file_id = app.media.put(file.read(),
                                    filename=final_file_name,
                                    content_type=content_type,
                                    # version = version
                                    )

@celery.task(soft_time_limit=1800)
def publish_bloglist_embed_on_s3():
    if type(app.media).__name__ is not 'AmazonMediaStorage':
        pass
    else:
        assets = bloglist_assets()
        # publish version file to get the asset_root
        version_file = os.path.join(BLOGSLIST_ASSETS_DIR, assets.get('version'))
        # remove existing first
        app.media.delete(app.media.media_id(version_file,
                                            content_type='application/json'
                                            # version=version
                                            ))
        # upload
        file_id = app.media.put(open(os.path.join(BLOGSLIST_DIRECTORY, version_file), 'rb').read(),
                                filename=version_file,
                                content_type='application/json'
                                # version = version
                                )

        assets_public_url = superdesk.upload.url_for_media(file_id).replace(assets['version'], '').replace('http://', '//')

        html = render_bloglist_embed(assets_root=assets_public_url)
        file_path = get_file_path()
        # remove existing
        app.media.delete(app.media.media_id(file_path, version=False))
        # upload
        file_id = app.media.put(io.BytesIO(bytes(html, 'utf-8')),
                                filename=file_path,
                                content_type='text/html',
                                version=False)
        public_url = superdesk.upload.url_for_media(file_id)
        # retrieves all opened blogs
        blogslist_service = get_resource_service('blogslist')
        for blogslist in blogslist_service.get(req=None, lookup=dict(key='bloglist')):
            get_resource_service('blogslist').system_update(blogslist['_id'], {'value': public_url}, blogslist)
        else:
            blogslist_service.create([{'key': 'bloglist', 'value': public_url}])

        # publish_assets('template')
        publish_assets('scripts')
        publish_assets('styles')

def check_media_storage():
    if type(app.media).__name__ is not 'AmazonMediaStorage':
        raise MediaStorageUnsupportedForBlogPublishing()

def render_bloglist_embed(api_host=None, assets_root=None):
    compiled_api_host = "{}://{}{}".format(
        app.config['URL_PROTOCOL'],
        app.config['SERVER_NAME'],
        '/' + app.config['URL_PREFIX']  if app.config['URL_PREFIX'] else '')
    api_host = api_host or compiled_api_host
    assets_root = assets_root or BLOGSLIST_ASSETS_DIR + '/'
    assets = bloglist_assets();
    # compute path relative to the assets_root for `styles` and `scripts`
    for index, script in enumerate(assets.get('scripts')):
        assets['scripts'][index] = os.path.join(assets_root, script)
    for index, style in enumerate(assets.get('styles')):
        assets['styles'][index] = os.path.join(assets_root, style)

    scope = {
        'debug': app.config.get('LIVEBLOG_DEBUG'),
        'api_host': api_host,
        'assets': assets,
        'assets_root': assets_root
    }
    return render_template('blog-list-embed.html', **scope)

@bp.route('/blogslist_embed')
def blogslist_embed(api_host=None, assets_root=None):
    return render_bloglist_embed(api_host=api_host, assets_root=assets_root)

class BlogsListResource(Resource):

    datasource = {
        'source': 'blog_list'
    }
    schema = {
        'key': {'type': 'string', 'required': True, 'unique': True},
        'value': {'type': 'string'}
    }
    RESOURCE_METHODS = ['GET', 'POST', 'PATCH']
    privileges = {'GET': 'generic', 'POST': 'generic',
                  'PATCH': 'generic'}

class BlogsListService(BaseService):

    def publish_bloglist_embed_on_s3(self):
        publish_bloglist_embed_on_s3()

@bp.app_template_filter('tojson')
def tojson(obj):
    return json.dumps(obj, cls=MongoJSONEncoder)

class BloglistCommand(superdesk.Command):

    def run(self):
        blogslist_service = get_resource_service('blogslist')
        blogslist_service.publish_bloglist_embed_on_s3()
        print("Bloglist published to s3")

superdesk.command('register_bloglist', BloglistCommand())

<commit_msg>fix: `/api` path shouldn't be included.<commit_after># -*- coding: utf-8; -*-
#
# This file is part of Superdesk.
#
# Copyright 2013, 2014 Sourcefabric z.u. and contributors.
#
# For the full copyright and license information, please see the
# AUTHORS and LICENSE files distributed with this source code, or
# at https://www.sourcefabric.org/superdesk/license
import superdesk
from superdesk.resource import Resource
from superdesk.services import BaseService
from superdesk import get_resource_service
from flask import render_template, json, request, current_app as app
import os
import io
import magic
from superdesk.celery_app import celery
from eve.io.mongo import MongoJSONEncoder
import logging

logger = logging.getLogger('superdesk')
BLOGSLIST_DIRECTORY = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir, 'blogslist'))
BLOGSLIST_ASSETS_DIR = 'blogslist_assets'
CONTENT_TYPES = {
    '.css': 'text/css',
    '.js': 'application/javascript',
    '.json': 'application/json'
}

bp = superdesk.Blueprint('embed_blogslist', __name__, template_folder='templates')
bloglist_assets_blueprint = superdesk.Blueprint('blogslist_assets', __name__, static_folder=BLOGSLIST_ASSETS_DIR)

def bloglist_assets():
    return {
            'scripts': [
                'vendors/moment/min/moment-with-locales.min.js',
                'vendors/angular/angular.min.js',
                'vendors/angular-resource/angular-resource.min.js',
                'vendors/angular-route/angular-route.min.js',
                'vendors/angular-gettext/dist/angular-gettext.min.js',
                # 'templates.js',
                'main.js'
            ],
            'styles': [
                'styles/embed.css',
                'styles/reset.css'
            ],
            # 'template': ['template.html'],
            'version': 'bower.json'
        }

def get_file_path():
    return os.path.join(BLOGSLIST_ASSETS_DIR, 'index.html')

@celery.task(soft_time_limit=1800)
def publish_assets(asset_type):
    assets = bloglist_assets()
    # version_path = os.path.join(BLOGSLIST_DIRECTORY, BLOGSLIST_ASSETS_DIR, assets['version'])
    # # loads version json from file
    # version = json.loads(open(version_path, 'rb').read()).get('version', '0.0.0')
    # Save the file in the media storage if needed
    for name in (assets[asset_type]):
        asset_file = os.path.join(BLOGSLIST_DIRECTORY, BLOGSLIST_ASSETS_DIR, name)
        with open(asset_file, 'rb') as file:
            # set the content type
            mime = magic.Magic(mime=True)
            content_type = mime.from_file(asset_file)
            if content_type == 'text/plain' and name.endswith(tuple(CONTENT_TYPES.keys())):
                content_type = CONTENT_TYPES[os.path.splitext(name)[1]]
            final_file_name = os.path.join(BLOGSLIST_ASSETS_DIR, name)
            # remove existing first
            app.media.delete(app.media.media_id(final_file_name,
                                                content_type=content_type,
                                                # version=version
                                                ))
            # upload
            file_id = app.media.put(file.read(),
                                    filename=final_file_name,
                                    content_type=content_type,
                                    # version = version
                                    )

@celery.task(soft_time_limit=1800)
def publish_bloglist_embed_on_s3():
    if type(app.media).__name__ is not 'AmazonMediaStorage':
        pass
    else:
        assets = bloglist_assets()
        # publish version file to get the asset_root
        version_file = os.path.join(BLOGSLIST_ASSETS_DIR, assets.get('version'))
        # remove existing first
        app.media.delete(app.media.media_id(version_file,
                                            content_type='application/json'
                                            # version=version
                                            ))
        # upload
        file_id = app.media.put(open(os.path.join(BLOGSLIST_DIRECTORY, version_file), 'rb').read(),
                                filename=version_file,
                                content_type='application/json'
                                # version = version
                                )

        assets_public_url = superdesk.upload.url_for_media(file_id).replace(assets['version'], '').replace('http://', '//')

        html = render_bloglist_embed(assets_root=assets_public_url)
        file_path = get_file_path()
        # remove existing
        app.media.delete(app.media.media_id(file_path, version=False))
        # upload
        file_id = app.media.put(io.BytesIO(bytes(html, 'utf-8')),
                                filename=file_path,
                                content_type='text/html',
                                version=False)
        public_url = superdesk.upload.url_for_media(file_id)
        # retrieves all opened blogs
        blogslist_service = get_resource_service('blogslist')
        for blogslist in blogslist_service.get(req=None, lookup=dict(key='bloglist')):
            get_resource_service('blogslist').system_update(blogslist['_id'], {'value': public_url}, blogslist)
        else:
            blogslist_service.create([{'key': 'bloglist', 'value': public_url}])

        # publish_assets('template')
        publish_assets('scripts')
        publish_assets('styles')

def check_media_storage():
    if type(app.media).__name__ is not 'AmazonMediaStorage':
        raise MediaStorageUnsupportedForBlogPublishing()

def render_bloglist_embed(api_host=None, assets_root=None):
    compiled_api_host = "{}://{}/".format(
        app.config['URL_PROTOCOL'],
        app.config['SERVER_NAME'])
    api_host = api_host or compiled_api_host
    assets_root = assets_root or BLOGSLIST_ASSETS_DIR + '/'
    assets = bloglist_assets();
    # compute path relative to the assets_root for `styles` and `scripts`
    for index, script in enumerate(assets.get('scripts')):
        assets['scripts'][index] = os.path.join(assets_root, script)
    for index, style in enumerate(assets.get('styles')):
        assets['styles'][index] = os.path.join(assets_root, style)

    scope = {
        'debug': app.config.get('LIVEBLOG_DEBUG'),
        'api_host': api_host,
        'assets': assets,
        'assets_root': assets_root
    }
    return render_template('blog-list-embed.html', **scope)

@bp.route('/blogslist_embed')
def blogslist_embed(api_host=None, assets_root=None):
    return render_bloglist_embed(api_host=api_host, assets_root=assets_root)

class BlogsListResource(Resource):

    datasource = {
        'source': 'blog_list'
    }
    schema = {
        'key': {'type': 'string', 'required': True, 'unique': True},
        'value': {'type': 'string'}
    }
    RESOURCE_METHODS = ['GET', 'POST', 'PATCH']
    privileges = {'GET': 'generic', 'POST': 'generic',
                  'PATCH': 'generic'}

class BlogsListService(BaseService):

    def publish_bloglist_embed_on_s3(self):
        publish_bloglist_embed_on_s3()

@bp.app_template_filter('tojson')
def tojson(obj):
    return json.dumps(obj, cls=MongoJSONEncoder)

class BloglistCommand(superdesk.Command):

    def run(self):
        blogslist_service = get_resource_service('blogslist')
        blogslist_service.publish_bloglist_embed_on_s3()
        print("Bloglist published to s3")

superdesk.command('register_bloglist', BloglistCommand())

<|endoftext|>