<commit_before># Copyright 2004-2010 OpenERP SA
# Copyright 2014 Angel Moya <angel.moya@domatix.com>
# Copyright 2015 Pedro M. Baeza <pedro.baeza@tecnativa.com>
# Copyright 2016-2018 Carlos Dauden <carlos.dauden@tecnativa.com>
# Copyright 2016-2017 LasLabs Inc.
# Copyright 2018 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import api, fields, models
from odoo.exceptions import ValidationError
from odoo.tools.translate import _

class AccountAnalyticAccount(models.Model):
    _name = 'account.analytic.account'
    _inherit = [
        'account.analytic.account',
        'account.abstract.analytic.contract',
    ]

    contract_template_id = fields.Many2one(
        string='Contract Template', comodel_name='account.analytic.contract'
    )
    recurring_invoice_line_ids = fields.One2many(
        string='Invoice Lines',
        comodel_name='account.analytic.invoice.line',
        inverse_name='contract_id',
        copy=True,
    )
    recurring_invoices = fields.Boolean(
        string='Generate recurring invoices automatically'
    )
    user_id = fields.Many2one(
        comodel_name='res.users',
        string='Responsible',
        index=True,
        default=lambda self: self.env.user,
    )
    create_invoice_visibility = fields.Boolean(
        compute='_compute_create_invoice_visibility'
    )
    recurring_next_date = fields.Date(
        compute='_compute_recurring_next_date',
        string='Date of Next Invoice',
        store=True,
    )
    date_end = fields.Date(
        compute='_compute_date_end', string='Date End', store=True
    )
    payment_term_id = fields.Many2one(
        comodel_name='account.payment.term', string='Payment Terms'
    )
    invoice_count = fields.Integer(compute="_compute_invoice_count")

    @api.multi
    def _get_related_invoices(self):
        self.ensure_one()

        invoices = (
            self.env['account.invoice.line']
            .search(
                [
                    (
                        'contract_line_id',
                        'in',
                        self.recurring_invoice_line_ids.ids,
                    )
                ]
            )
            .mapped('invoice_id')
        )
        invoices |= self.env['account.invoice'].search(
            [('old_contract_id', '=', self.id)]
        )
        return invoices

    @api.multi
    def _compute_invoice_count(self):
        for rec in self:
            rec.invoice_count = len(rec._get_related_invoices())

    @api.multi
    def action_show_invoices(self):
        self.ensure_one()
        return {
            'type': 'ir.actions.act_window',
            'name': 'Invoices',
            'res_model': 'account.invoice',
            'view_type': 'form',
            'view_mode': 'tree,kanban,form,calendar,pivot,graph,activity',
            'domain': [('id', 'in', self._get_related_invoices().ids)],
        }

    @api.depends('recurring_invoice_line_ids.date_end')
    def _compute_date_end(self):
        for contract in self:
            contract.date_end = False
            date_end = contract.recurring_invoice_line_ids.mapped('date_end')
            if date_end and all(date_end):
                contract.date_end = max(date_end)

    @api.depends(
        'recurring_invoice_line_ids.recurring_next_date',
        'recurring_invoice_line_ids.is_canceled',
    )
    def _compute_recurring_next_date(self):
        for contract in self:
            recurring_next_date = contract.recurring_invoice_line_ids.filtered(
                lambda l: l.recurring_next_date and not l.is_canceled
            ).mapped('recurring_next_date')
            if recurring_next_date:
                contract.recurring_next_date = min(recurring_next_date)

    @api.depends('recurring_invoice_line_ids.create_invoice_visibility')
    def _compute_create_invoice_visibility(self):
        for contract in self:
            contract.create_invoice_visibility = any(
                contract.recurring_invoice_line_ids.mapped(
                    'create_invoice_visibility'
                )
            )

    @api.onchange('contract_template_id')
    def _onchange_contract_template_id(self):
        """Update the contract fields with that of the template.

        Take special consideration with the `recurring_invoice_line_ids`,
        which must be created using the data from the contract lines. Cascade
        deletion ensures that any errant lines that are created are also
        deleted.
        """
        contract_template_id = self.contract_template_id
        if not contract_template_id:
            return
        for field_name, field in contract_template_id._fields.items():
            if field.name == 'recurring_invoice_line_ids':
                lines = self._convert_contract_lines(contract_template_id)
                self.recurring_invoice_line_ids = lines
            elif not any(
                (
                    field.compute,
                    field.related,
                    field.automatic,
                    field.readonly,
                    field.company_dependent,
                    field.name in self.NO_SYNC,
                )
            ):
                self[field_name] = self.contract_template_id[field_name]

    @api.onchange('partner_id')
    def _onchange_partner_id(self):
        self.pricelist_id = self.partner_id.property_product_pricelist.id

    @api.constrains('partner_id', 'recurring_invoices')
    def _check_partner_id_recurring_invoices(self):
        for contract in self.filtered('recurring_invoices'):
            if not contract.partner_id:
                raise ValidationError(
                    _("You must supply a partner for the contract '%s'")
                    % contract.name
                )

    @api.multi
    def _convert_contract_lines(self, contract):
        self.ensure_one()
        new_lines = []
        for contract_line in contract.recurring_invoice_line_ids:
            vals = contract_line._convert_to_write(contract_line.read()[0])
            # Remove template link field
            vals.pop('contract_template_id', False)
            vals['date_start'] = fields.Date.context_today(contract_line)
            vals['recurring_next_date'] = fields.Date.context_today(
                contract_line
            )
            self.recurring_invoice_line_ids._onchange_date_start()
            new_lines.append((0, 0, vals))
        return new_lines

    @api.multi
    def _prepare_invoice(self, date_invoice, journal=None):
        self.ensure_one()
        if not journal:
            journal = (
                self.journal_id
                if self.journal_id.type == self.contract_type
                else self.env['account.journal'].search(
                    [
                        ('type', '=', self.contract_type),
                        ('company_id', '=', self.company_id.id),
                    ],
                    limit=1,
                )
            )
        if not journal:
            raise ValidationError(
                _("Please define a %s journal for the company '%s'.")
                % (self.contract_type, self.company_id.name or '')
            )
        currency = (
            self.pricelist_id.currency_id
            or self.partner_id.property_product_pricelist.currency_id
            or self.company_id.currency_id
        )
        invoice_type = 'out_invoice'
        if self.contract_type == 'purchase':
            invoice_type = 'in_invoice'
        return {
            'reference': self.code,
            'type': invoice_type,
            'partner_id': self.partner_id.address_get(['invoice'])['invoice'],
            'currency_id': currency.id,
            'date_invoice': date_invoice,
            'journal_id': journal.id,
            'origin': self.name,
            'company_id': self.company_id.id,
            'user_id': self.partner_id.user_id.id,
        }

    @api.multi
    def action_contract_send(self):
        self.ensure_one()
        template = self.env.ref('contract.email_contract_template', False)
        compose_form = self.env.ref('mail.email_compose_message_wizard_form')
        ctx = dict(
            default_model='account.analytic.account',
            default_res_id=self.id,
            default_use_template=bool(template),
            default_template_id=template and template.id or False,
            default_composition_mode='comment',
        )
        return {
            'name': _('Compose Email'),
            'type': 'ir.actions.act_window',
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'mail.compose.message',
            'views': [(compose_form.id, 'form')],
            'view_id': compose_form.id,
            'target': 'new',
            'context': ctx,
        }

    @api.model
    def _finalize_invoice_values(self, invoice_values):
        """
        This method adds the missing values in the invoice lines dictionaries.

        If no account on the product, the invoice lines account is
        taken from the invoice's journal in _onchange_product_id
        This code is not in finalize_creation_from_contract because it's
        not possible to create an invoice line with no account

        :param invoice_values: dictionary (invoice values)
        :return: updated dictionary (invoice values)
        """
        # If no account on the product, the invoice lines account is
        # taken from the invoice's journal in _onchange_product_id
        # This code is not in finalize_creation_from_contract because it's
        # not possible to create an invoice line with no account
        new_invoice = self.env['account.invoice'].new(invoice_values)
        for invoice_line in new_invoice.invoice_line_ids:
            name = invoice_line.name
            account_analytic_id = invoice_line.account_analytic_id
            price_unit = invoice_line.price_unit
            invoice_line.invoice_id = new_invoice
            invoice_line._onchange_product_id()
            invoice_line.update(
                {
                    'name': name,
                    'account_analytic_id': account_analytic_id,
                    'price_unit': price_unit,
                }
            )
        return new_invoice._convert_to_write(new_invoice._cache)

    @api.model
    def _finalize_invoice_creation(self, invoices):
        for invoice in invoices:
            invoice._onchange_partner_id()
        invoices.compute_taxes()

    @api.model
    def _finalize_and_create_invoices(self, invoices_values):
        """
        This method:
         - finalizes the invoices values (onchange's...)
         - creates the invoices
         - finalizes the created invoices (onchange's, tax computation...)
        :param invoices_values: list of dictionaries (invoices values)
        :return: created invoices (account.invoice)
        """
        if isinstance(invoices_values, dict):
            invoices_values = [invoices_values]
        final_invoices_values = []
        for invoice_values in invoices_values:
            final_invoices_values.append(
                self._finalize_invoice_values(invoice_values)
            )
        invoices = self.env['account.invoice'].create(final_invoices_values)
        self._finalize_invoice_creation(invoices)
        return invoices

    @api.model
    def _get_contracts_to_invoice_domain(self, date_ref=None):
        """
        This method builds the domain to use to find all
        contracts (account.analytic.account) to invoice.
        :param date_ref: optional reference date to use instead of today
        :return: list (domain) usable on account.analytic.account
        """
        domain = []
        if not date_ref:
            date_ref = fields.Date.context_today(self)
        domain.extend(
            [
                ('recurring_invoices', '=', True),
                ('recurring_next_date', '<=', date_ref),
            ]
        )
        return domain

    @api.multi
    def _get_lines_to_invoice(self, date_ref):
        """
        This method fetches and returns the lines to invoice on the contract
        (self), based on the given date.
        :param date_ref: date used as reference date to find lines to invoice
        :return: contract lines (account.analytic.invoice.line recordset)
        """
        self.ensure_one()
        return self.recurring_invoice_line_ids.filtered(
            lambda l: not l.is_canceled
            and l.recurring_next_date
            and l.recurring_next_date <= date_ref
        )

    @api.multi
    def _prepare_recurring_invoices_values(self, date_ref=False):
        """
        This method builds the list of invoices values to create, based on
        the lines to invoice of the contracts in self.
        !!! The date of next invoice (recurring_next_date) is updated here !!!
        :return: list of dictionaries (invoices values)
        """
        invoices_values = []
        for contract in self:
            if not date_ref:
                date_ref = contract.recurring_next_date
            if not date_ref:
                # this use case is possible when recurring_create_invoice is
                # called for a finished contract
                continue
            contract_lines = contract._get_lines_to_invoice(date_ref)
            if not contract_lines:
                continue
            invoice_values = contract._prepare_invoice(date_ref)
            for line in contract_lines:
                invoice_values.setdefault('invoice_line_ids', [])
                invoice_line_values = line._prepare_invoice_line(
                    invoice_id=False
                )
                if invoice_line_values:
                    invoice_values['invoice_line_ids'].append(
                        (0, 0, invoice_line_values)
                    )
            invoices_values.append(invoice_values)
            contract_lines._update_recurring_next_date()
        return invoices_values

    @api.multi
    def recurring_create_invoice(self):
        """
        This method triggers the creation of the next invoices of the contracts
        even if their next invoicing date is in the future.
        """
        return self._recurring_create_invoice()

    @api.multi
    def _recurring_create_invoice(self, date_ref=False):
        invoices_values = self._prepare_recurring_invoices_values(date_ref)
        return self._finalize_and_create_invoices(invoices_values)

    @api.model
    def cron_recurring_create_invoice(self):
        domain = self._get_contracts_to_invoice_domain()
        contracts_to_invoice = self.search(domain)
        date_ref = fields.Date.context_today(contracts_to_invoice)
        contracts_to_invoice._recurring_create_invoice(date_ref)
<commit_msg>[FIX] Contract: copy payment term on generated invoice<commit_after># Copyright 2004-2010 OpenERP SA
# Copyright 2014 Angel Moya <angel.moya@domatix.com>
# Copyright 2015 Pedro M. Baeza <pedro.baeza@tecnativa.com>
# Copyright 2016-2018 Carlos Dauden <carlos.dauden@tecnativa.com>
# Copyright 2016-2017 LasLabs Inc.
# Copyright 2018 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import api, fields, models
from odoo.exceptions import ValidationError
from odoo.tools.translate import _

class AccountAnalyticAccount(models.Model):
    _name = 'account.analytic.account'
    _inherit = [
        'account.analytic.account',
        'account.abstract.analytic.contract',
    ]

    contract_template_id = fields.Many2one(
        string='Contract Template', comodel_name='account.analytic.contract'
    )
    recurring_invoice_line_ids = fields.One2many(
        string='Invoice Lines',
        comodel_name='account.analytic.invoice.line',
        inverse_name='contract_id',
        copy=True,
    )
    recurring_invoices = fields.Boolean(
        string='Generate recurring invoices automatically'
    )
    user_id = fields.Many2one(
        comodel_name='res.users',
        string='Responsible',
        index=True,
        default=lambda self: self.env.user,
    )
    create_invoice_visibility = fields.Boolean(
        compute='_compute_create_invoice_visibility'
    )
    recurring_next_date = fields.Date(
        compute='_compute_recurring_next_date',
        string='Date of Next Invoice',
        store=True,
    )
    date_end = fields.Date(
        compute='_compute_date_end', string='Date End', store=True
    )
    payment_term_id = fields.Many2one(
        comodel_name='account.payment.term', string='Payment Terms'
    )
    invoice_count = fields.Integer(compute="_compute_invoice_count")

    @api.multi
    def _get_related_invoices(self):
        self.ensure_one()

        invoices = (
            self.env['account.invoice.line']
            .search(
                [
                    (
                        'contract_line_id',
                        'in',
                        self.recurring_invoice_line_ids.ids,
                    )
                ]
            )
            .mapped('invoice_id')
        )
        invoices |= self.env['account.invoice'].search(
            [('old_contract_id', '=', self.id)]
        )
        return invoices

    @api.multi
    def _compute_invoice_count(self):
        for rec in self:
            rec.invoice_count = len(rec._get_related_invoices())

    @api.multi
    def action_show_invoices(self):
        self.ensure_one()
        return {
            'type': 'ir.actions.act_window',
            'name': 'Invoices',
            'res_model': 'account.invoice',
            'view_type': 'form',
            'view_mode': 'tree,kanban,form,calendar,pivot,graph,activity',
            'domain': [('id', 'in', self._get_related_invoices().ids)],
        }

    @api.depends('recurring_invoice_line_ids.date_end')
    def _compute_date_end(self):
        for contract in self:
            contract.date_end = False
            date_end = contract.recurring_invoice_line_ids.mapped('date_end')
            if date_end and all(date_end):
                contract.date_end = max(date_end)

    @api.depends(
        'recurring_invoice_line_ids.recurring_next_date',
        'recurring_invoice_line_ids.is_canceled',
    )
    def _compute_recurring_next_date(self):
        for contract in self:
            recurring_next_date = contract.recurring_invoice_line_ids.filtered(
                lambda l: l.recurring_next_date and not l.is_canceled
            ).mapped('recurring_next_date')
            if recurring_next_date:
                contract.recurring_next_date = min(recurring_next_date)

    @api.depends('recurring_invoice_line_ids.create_invoice_visibility')
    def _compute_create_invoice_visibility(self):
        for contract in self:
            contract.create_invoice_visibility = any(
                contract.recurring_invoice_line_ids.mapped(
                    'create_invoice_visibility'
                )
            )

    @api.onchange('contract_template_id')
    def _onchange_contract_template_id(self):
        """Update the contract fields with that of the template.

        Take special consideration with the `recurring_invoice_line_ids`,
        which must be created using the data from the contract lines. Cascade
        deletion ensures that any errant lines that are created are also
        deleted.
        """
        contract_template_id = self.contract_template_id
        if not contract_template_id:
            return
        for field_name, field in contract_template_id._fields.items():
            if field.name == 'recurring_invoice_line_ids':
                lines = self._convert_contract_lines(contract_template_id)
                self.recurring_invoice_line_ids = lines
            elif not any(
                (
                    field.compute,
                    field.related,
                    field.automatic,
                    field.readonly,
                    field.company_dependent,
                    field.name in self.NO_SYNC,
                )
            ):
                self[field_name] = self.contract_template_id[field_name]

    @api.onchange('partner_id')
    def _onchange_partner_id(self):
        self.pricelist_id = self.partner_id.property_product_pricelist.id

    @api.constrains('partner_id', 'recurring_invoices')
    def _check_partner_id_recurring_invoices(self):
        for contract in self.filtered('recurring_invoices'):
            if not contract.partner_id:
                raise ValidationError(
                    _("You must supply a partner for the contract '%s'")
                    % contract.name
                )

    @api.multi
    def _convert_contract_lines(self, contract):
        self.ensure_one()
        new_lines = []
        for contract_line in contract.recurring_invoice_line_ids:
            vals = contract_line._convert_to_write(contract_line.read()[0])
            # Remove template link field
            vals.pop('contract_template_id', False)
            vals['date_start'] = fields.Date.context_today(contract_line)
            vals['recurring_next_date'] = fields.Date.context_today(
                contract_line
            )
            self.recurring_invoice_line_ids._onchange_date_start()
            new_lines.append((0, 0, vals))
        return new_lines

    @api.multi
    def _prepare_invoice(self, date_invoice, journal=None):
        self.ensure_one()
        if not journal:
            journal = (
                self.journal_id
                if self.journal_id.type == self.contract_type
                else self.env['account.journal'].search(
                    [
                        ('type', '=', self.contract_type),
                        ('company_id', '=', self.company_id.id),
                    ],
                    limit=1,
                )
            )
        if not journal:
            raise ValidationError(
                _("Please define a %s journal for the company '%s'.")
                % (self.contract_type, self.company_id.name or '')
            )
        currency = (
            self.pricelist_id.currency_id
            or self.partner_id.property_product_pricelist.currency_id
            or self.company_id.currency_id
        )
        invoice_type = 'out_invoice'
        if self.contract_type == 'purchase':
            invoice_type = 'in_invoice'
        return {
            'reference': self.code,
            'type': invoice_type,
            'partner_id': self.partner_id.address_get(['invoice'])['invoice'],
            'currency_id': currency.id,
            'date_invoice': date_invoice,
            'journal_id': journal.id,
            'origin': self.name,
            'company_id': self.company_id.id,
            'user_id': self.partner_id.user_id.id,
            'payment_term_id': self.payment_term_id.id,
        }

    @api.multi
    def action_contract_send(self):
        self.ensure_one()
        template = self.env.ref('contract.email_contract_template', False)
        compose_form = self.env.ref('mail.email_compose_message_wizard_form')
        ctx = dict(
            default_model='account.analytic.account',
            default_res_id=self.id,
            default_use_template=bool(template),
            default_template_id=template and template.id or False,
            default_composition_mode='comment',
        )
        return {
            'name': _('Compose Email'),
            'type': 'ir.actions.act_window',
            'view_type': 'form',
            'view_mode': 'form',
            'res_model': 'mail.compose.message',
            'views': [(compose_form.id, 'form')],
            'view_id': compose_form.id,
            'target': 'new',
            'context': ctx,
        }

    @api.model
    def _finalize_invoice_values(self, invoice_values):
        """
        This method adds the missing values in the invoice lines dictionaries.

        If no account on the product, the invoice lines account is
        taken from the invoice's journal in _onchange_product_id
        This code is not in finalize_creation_from_contract because it's
        not possible to create an invoice line with no account

        :param invoice_values: dictionary (invoice values)
        :return: updated dictionary (invoice values)
        """
        # If no account on the product, the invoice lines account is
        # taken from the invoice's journal in _onchange_product_id
        # This code is not in finalize_creation_from_contract because it's
        # not possible to create an invoice line with no account
        new_invoice = self.env['account.invoice'].new(invoice_values)
        for invoice_line in new_invoice.invoice_line_ids:
            name = invoice_line.name
            account_analytic_id = invoice_line.account_analytic_id
            price_unit = invoice_line.price_unit
            invoice_line.invoice_id = new_invoice
            invoice_line._onchange_product_id()
            invoice_line.update(
                {
                    'name': name,
                    'account_analytic_id': account_analytic_id,
                    'price_unit': price_unit,
                }
            )
        return new_invoice._convert_to_write(new_invoice._cache)

    @api.model
    def _finalize_invoice_creation(self, invoices):
        for invoice in invoices:
            payment_term = invoice.payment_term_id
            invoice._onchange_partner_id()
            invoice.payment_term_id = payment_term
        invoices.compute_taxes()

    @api.model
    def _finalize_and_create_invoices(self, invoices_values):
        """
        This method:
         - finalizes the invoices values (onchange's...)
         - creates the invoices
         - finalizes the created invoices (onchange's, tax computation...)
        :param invoices_values: list of dictionaries (invoices values)
        :return: created invoices (account.invoice)
        """
        if isinstance(invoices_values, dict):
            invoices_values = [invoices_values]
        final_invoices_values = []
        for invoice_values in invoices_values:
            final_invoices_values.append(
                self._finalize_invoice_values(invoice_values)
            )
        invoices = self.env['account.invoice'].create(final_invoices_values)
        self._finalize_invoice_creation(invoices)
        return invoices

    @api.model
    def _get_contracts_to_invoice_domain(self, date_ref=None):
        """
        This method builds the domain to use to find all
        contracts (account.analytic.account) to invoice.
        :param date_ref: optional reference date to use instead of today
        :return: list (domain) usable on account.analytic.account
        """
        domain = []
        if not date_ref:
            date_ref = fields.Date.context_today(self)
        domain.extend(
            [
                ('recurring_invoices', '=', True),
                ('recurring_next_date', '<=', date_ref),
            ]
        )
        return domain

    @api.multi
    def _get_lines_to_invoice(self, date_ref):
        """
        This method fetches and returns the lines to invoice on the contract
        (self), based on the given date.
        :param date_ref: date used as reference date to find lines to invoice
        :return: contract lines (account.analytic.invoice.line recordset)
        """
        self.ensure_one()
        return self.recurring_invoice_line_ids.filtered(
            lambda l: not l.is_canceled
            and l.recurring_next_date
            and l.recurring_next_date <= date_ref
        )

    @api.multi
    def _prepare_recurring_invoices_values(self, date_ref=False):
        """
        This method builds the list of invoices values to create, based on
        the lines to invoice of the contracts in self.
        !!! The date of next invoice (recurring_next_date) is updated here !!!
        :return: list of dictionaries (invoices values)
        """
        invoices_values = []
        for contract in self:
            if not date_ref:
                date_ref = contract.recurring_next_date
            if not date_ref:
                # this use case is possible when recurring_create_invoice is
                # called for a finished contract
                continue
            contract_lines = contract._get_lines_to_invoice(date_ref)
            if not contract_lines:
                continue
            invoice_values = contract._prepare_invoice(date_ref)
            for line in contract_lines:
                invoice_values.setdefault('invoice_line_ids', [])
                invoice_line_values = line._prepare_invoice_line(
                    invoice_id=False
                )
                if invoice_line_values:
                    invoice_values['invoice_line_ids'].append(
                        (0, 0, invoice_line_values)
                    )
            invoices_values.append(invoice_values)
            contract_lines._update_recurring_next_date()
        return invoices_values

    @api.multi
    def recurring_create_invoice(self):
        """
        This method triggers the creation of the next invoices of the contracts
        even if their next invoicing date is in the future.
        """
        return self._recurring_create_invoice()

    @api.multi
    def _recurring_create_invoice(self, date_ref=False):
        invoices_values = self._prepare_recurring_invoices_values(date_ref)
        return self._finalize_and_create_invoices(invoices_values)

    @api.model
    def cron_recurring_create_invoice(self):
        domain = self._get_contracts_to_invoice_domain()
        contracts_to_invoice = self.search(domain)
        date_ref = fields.Date.context_today(contracts_to_invoice)
        contracts_to_invoice._recurring_create_invoice(date_ref)
<|endoftext|>


<commit_before>import hashlib
import logging

from datetime import datetime
from flask.ext.sqlalchemy import SQLAlchemy
from sqlalchemy import func, Column, Integer, String, DateTime

db = SQLAlchemy()

def hash_phone(number):
    # takes phone number and returns 64 charachter string
    return hashlib.sha256(number).hexdigest()

def to_dict(model):
    d = model.__dict__
    d.pop('_sa_instance_state')

    return d

db.Model.to_dict = to_dict

class Call(db.Model):
    __tablename__ = 'calls'

    id = Column(Integer, primary_key=True)
    timestamp = Column(DateTime)
    campaign_id = Column(String(10))
    member_id = Column(String(10))  # congress member sunlight identifier

    # user attributes
    user_id = Column(String(64))    # hashed phone number
    zipcode = Column(String(5))
    areacode = Column(String(3))    # first 3 digits of phone number
    exchange = Column(String(3))    # next 3 digits of phone number

    # twilio attributes
    call_id = Column(String(40))    # twilio call ID
    status = Column(String(25))     # twilio call status
    duration = Column(Integer)      # twilio call time in seconds

    def __init__(self, campaign_id, member_id, zipcode=None, phone_number=None,
                 call_id=None, status='unknown', duration=0):
        self.timestamp = datetime.now()
        self.status = status
        self.duration = duration
        self.campaign_id = campaign_id
        self.member_id = member_id
        self.call_id = call_id

        if phone_number:
            phone_number = phone_number.replace('-', '').replace('.', '')
            self.user_id = hash_phone(phone_number)
            self.areacode = phone_number[:3]
            self.exchange = phone_number[3:6]

        self.zipcode = zipcode

    def __repr__(self):
        return '<Call {}-{}-xxxx to {}>'.format(
            self.areacode, self.exchange, self.member_id)

def log_call(db, params, campaign, request):
    try:
        i = int(request.values.get('call_index'))

        kwds = dict(
            campaign_id=campaign['id'],
            member_id=params['repIds'][i],
            zipcode=params['zipcode'],
            phone_number=params['userPhone'],
            call_id=request.values.get('CallSid', None),  # twilio call id
            status=request.values.get('DialCallStatus', 'unknown'),
            duration=request.values.get('DialCallDuration', 0))

        db.session.add(Call(**kwds))
        db.session.commit()
    except:
        logging.error('Failed to log call: {}'.format(kwds))

def call_count(db):
    try:
        return dict(count=db.session.query(func.Count(Call.zipcode)).all()[0][0])
    except:
        return 0

def aggregate_stats(cid):
    zipcodes = db.session.query(Call.zipcode, func.Count(Call.zipcode)) \
        .filter(Call.campaign_id == cid) \
        .group_by(Call.zipcode).all()

    reps = db.session.query(Call.member_id, func.Count(Call.member_id)) \
        .filter(Call.campaign_id == cid) \
        .group_by(Call.member_id).all()

    return dict(calls=dict(
        zipcodes=dict(tuple(z) for z in zipcodes),
        reps=dict(tuple(r) for r in reps)))

def setUp(app):
    db.app = app
    db.drop_all()
    db.create_all()

def tearDown(app):
    db.app = app
    db.drop_all()

if __name__ == "__main__":
    # initialize db
    from app import app
    setUp(app)
<commit_msg>Prefer real dict, log exception<commit_after>import hashlib
import logging

from datetime import datetime
from flask.ext.sqlalchemy import SQLAlchemy
from sqlalchemy import func, Column, Integer, String, DateTime

db = SQLAlchemy()

def hash_phone(number):
    # takes phone number and returns 64 charachter string
    return hashlib.sha256(number).hexdigest()

def to_dict(model):
    d = model.__dict__
    d.pop('_sa_instance_state')

    return d

db.Model.to_dict = to_dict

class Call(db.Model):
    __tablename__ = 'calls'

    id = Column(Integer, primary_key=True)
    timestamp = Column(DateTime)
    campaign_id = Column(String(10))
    member_id = Column(String(10))  # congress member sunlight identifier

    # user attributes
    user_id = Column(String(64))    # hashed phone number
    zipcode = Column(String(5))
    areacode = Column(String(3))    # first 3 digits of phone number
    exchange = Column(String(3))    # next 3 digits of phone number

    # twilio attributes
    call_id = Column(String(40))    # twilio call ID
    status = Column(String(25))     # twilio call status
    duration = Column(Integer)      # twilio call time in seconds

    def __init__(self, campaign_id, member_id, zipcode=None, phone_number=None,
                 call_id=None, status='unknown', duration=0):
        self.timestamp = datetime.now()
        self.status = status
        self.duration = duration
        self.campaign_id = campaign_id
        self.member_id = member_id
        self.call_id = call_id

        if phone_number:
            phone_number = phone_number.replace('-', '').replace('.', '')
            self.user_id = hash_phone(phone_number)
            self.areacode = phone_number[:3]
            self.exchange = phone_number[3:6]

        self.zipcode = zipcode

    def __repr__(self):
        return '<Call {}-{}-xxxx to {}>'.format(
            self.areacode, self.exchange, self.member_id)

def log_call(db, params, campaign, request):
    try:
        i = int(request.values.get('call_index'))

        kwds = {
            'campaign_id': campaign['id'],
            'member_id': params['repIds'][i],
            'zipcode': params['zipcode'],
            'phone_number': params['userPhone'],
            'call_id': request.values.get('CallSid', None),  # twilio call id
            'status': request.values.get('DialCallStatus', 'unknown'),
            'duration': request.values.get('DialCallDuration', 0)
        }

        db.session.add(Call(**kwds))
        db.session.commit()
    except Exception:
        logging.error('Failed to log call: Exception: {}'.format(kwds),
                      exc_info=True)

def call_count(db):
    try:
        return dict(count=db.session.query(func.Count(Call.zipcode)).all()[0][0])
    except:
        return 0

def aggregate_stats(cid):
    zipcodes = db.session.query(Call.zipcode, func.Count(Call.zipcode)) \
        .filter(Call.campaign_id == cid) \
        .group_by(Call.zipcode).all()

    reps = db.session.query(Call.member_id, func.Count(Call.member_id)) \
        .filter(Call.campaign_id == cid) \
        .group_by(Call.member_id).all()

    return dict(calls=dict(
        zipcodes=dict(tuple(z) for z in zipcodes),
        reps=dict(tuple(r) for r in reps)))

def setUp(app):
    db.app = app
    db.drop_all()
    db.create_all()

def tearDown(app):
    db.app = app
    db.drop_all()

if __name__ == "__main__":
    # initialize db
    from app import app
    setUp(app)
<|endoftext|>


<commit_before># Copyright 2015 Novo Nordisk Foundation Center for Biosustainability, DTU.

# 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.

from functools import partial, reduce
from cobra.core import Metabolite
from pandas import DataFrame
import six
from cameo.core.reaction import Reaction

class Pathway(object):
    def __init__(self, reactions, *args, **kwargs):
        super(Pathway, self).__init__(*args, **kwargs)
        self.reactions = reactions

    @property
    def data_frame(self):
        return DataFrame([[r.build_reaction_string(True), r.lower_bound, r.upper_bound] for r in self.reactions],
                         columns=["equation", "lower_bound", "upper_bound"], index=[r.id for r in self.reactions])

    @classmethod
    def from_file(cls, file_path, sep="\t"):
        reactions = []
        with open(file_path, "r") as pathway:
            for line in pathway:
                if line.startswith("#"):
                    continue
                line = line.strip("\n")

                identifier, equation, lower, upper, name, comments = line.split(sep)
                stoichiometry = _parse_equation(equation)
                reaction = _build_reaction(identifier, stoichiometry, float(upper), float(lower), name, comments)
                reactions.append(reaction)

        return cls(reactions)

    def to_file(self, file_path, sep="\t"):
        with open(file_path, "w") as output_file:
            for reaction in self.reactions:
                equation = _build_equation(reaction.metabolites)
                output_file.write(reaction.id + sep +
                                  equation + sep +
                                  reaction.lower_bound + sep +
                                  reaction.upper_bound + sep +
                                  reaction.name + sep +
                                  reaction.notes.get("pathway_note", "") + "\n")

    def plug_model(self, model, tm=None):
        metabolites = reduce(lambda x, y: x+y, [r.metabolites.keys() for r in self.reactions], [])
        exchanges = [model.add_demand(m, prefix="EX_", time_machine=tm) for m in metabolites if m not in model.metabolites]
        for exchange in exchanges:
            exchange.lower_bound = 0
        if tm is not None:
            tm(do=partial(model.add_reactions, self.reactions),
               undo=partial(model.remove_reactions, self.reactions, delete=False))
        else:
            model.add_reactions(self.reactions)

def _build_reaction(identifier, stoichiometry, upper, lower, name, comments):
    reaction = Reaction(identifier)
    reaction.name = name
    reaction.add_metabolites(stoichiometry)
    reaction.upper_bound = upper
    reaction.lower_bound = lower
    reaction.notes["pathway_note"] = comments
    return reaction

def _parse_equation(equation):
    stoichiometry = {}
    reactants, products = equation.split(" <=> ")
    for reactant in reactants.split(" + "):
        coeff, metabolite = reactant.split(" * ")
        name, metabolite_id = metabolite.split("#")
        met = Metabolite(id=metabolite_id, name=name)
        stoichiometry[met] = -float(coeff)

    for product in products.split(" + "):
        coeff, metabolite = product.split(" * ")
        name, metabolite_id = metabolite.split("#")
        met = Metabolite(id=metabolite_id, name=name)
        stoichiometry[met] = float(coeff)

    return stoichiometry

def _build_equation(stoichiometry):
    products = {m: v for m, v in six.iteritems(stoichiometry) if v > 0}
    reactants = {m: v for m, v in six.iteritems(stoichiometry) if v > 0}

    products = " + ".join(["%f * %s#%s" % (v, m.name, m.id) for m, v in products])
    reactants = " + ".join(["%f * %s#%s" % (-v, m.name, m.id) for m, v in reactants])
    return reactants + " <=> " + products<commit_msg>More documentation<commit_after># Copyright 2015 Novo Nordisk Foundation Center for Biosustainability, DTU.

# 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.

from functools import partial, reduce
from cobra.core import Metabolite
from pandas import DataFrame
import six
from cameo.core.reaction import Reaction

# TODO: Load pathways from SBML and JSON
# TODO: Define the product
# TODO: Visualization with ESCHER
class Pathway(object):
    """
    Representation of a pathway (a set of reactions)

    Attributes
    ----------

    reactions: list o Reaction
        The list of reactions in the pathway.

    """
    def __init__(self, reactions, *args, **kwargs):
        super(Pathway, self).__init__(*args, **kwargs)
        self.reactions = reactions

    @property
    def data_frame(self):
        return DataFrame([[r.build_reaction_string(True), r.lower_bound, r.upper_bound] for r in self.reactions],
                         columns=["equation", "lower_bound", "upper_bound"], index=[r.id for r in self.reactions])

    @classmethod
    def from_file(cls, file_path, sep="\t"):
        """
        Read a pathway from a file. The file format is:
        reaction_id<sep>equation<sep>lower_limit<sep>upper_limit<sep>name<sep>comments\n

        The equation is defined by:
        coefficient * substrate_name#substrate_id + ... <=> coefficient * product_name#product_id

        Arguments
        ---------

        file_path: str
            The path to the file containing the pathway
        sep: str
            The separator between elements in the file (default: "\t")

        Returns
        -------
        Pathway
        """
        reactions = []
        with open(file_path, "r") as pathway:
            for line in pathway:
                if line.startswith("#"):
                    continue
                line = line.strip("\n")

                identifier, equation, lower, upper, name, comments = line.split(sep)
                stoichiometry = _parse_equation(equation)
                reaction = _build_reaction(identifier, stoichiometry, float(upper), float(lower), name, comments)
                reactions.append(reaction)

        return cls(reactions)

    def to_file(self, file_path, sep="\t"):
        """
        Writes the pathway to a file.

        Arguments
        ---------

        file_path: str
            The path to the file where the pathway will be written
        sep: str
            The separator between elements in the file (default: "\t")

        See Also
        --------
        Pathway.from_file
        """
        with open(file_path, "w") as output_file:
            for reaction in self.reactions:
                equation = _build_equation(reaction.metabolites)
                output_file.write(reaction.id + sep +
                                  equation + sep +
                                  reaction.lower_bound + sep +
                                  reaction.upper_bound + sep +
                                  reaction.name + sep +
                                  reaction.notes.get("pathway_note", "") + "\n")

    def plug_model(self, model, tm=None):
        """
        Plugs the pathway to a model.
        If a TimeMachine is provided, the reactions will be removed after reverting the TimeMachine.

        Metabolites are matched in the model by id. For metabolites with no ID in the model, an exchange reaction
        is added to the model

        Arguments
        ---------
        model: SolverBasedModel
            The model to plug in the pathway
        tm: TimeMachine
            Optionally, a TimeMachine object can be added to the operation

        """
        metabolites = reduce(lambda x, y: x+y, [r.metabolites.keys() for r in self.reactions], [])
        exchanges = [model.add_demand(m, prefix="EX_", time_machine=tm) for m in metabolites
                     if m not in model.metabolites]
        for exchange in exchanges:
            exchange.lower_bound = 0
        if tm is not None:
            tm(do=partial(model.add_reactions, self.reactions),
               undo=partial(model.remove_reactions, self.reactions, delete=False))
        else:
            model.add_reactions(self.reactions)

def _build_reaction(identifier, stoichiometry, upper, lower, name, comments):
    reaction = Reaction(identifier)
    reaction.name = name
    reaction.add_metabolites(stoichiometry)
    reaction.upper_bound = upper
    reaction.lower_bound = lower
    reaction.notes["pathway_note"] = comments
    return reaction

def _parse_equation(equation):
    stoichiometry = {}
    reactants, products = equation.split(" <=> ")
    for reactant in reactants.split(" + "):
        coeff, metabolite = reactant.split(" * ")
        name, metabolite_id = metabolite.split("#")
        met = Metabolite(id=metabolite_id, name=name)
        stoichiometry[met] = -float(coeff)

    for product in products.split(" + "):
        coeff, metabolite = product.split(" * ")
        name, metabolite_id = metabolite.split("#")
        met = Metabolite(id=metabolite_id, name=name)
        stoichiometry[met] = float(coeff)

    return stoichiometry

def _build_equation(stoichiometry):
    products = {m: v for m, v in six.iteritems(stoichiometry) if v > 0}
    reactants = {m: v for m, v in six.iteritems(stoichiometry) if v > 0}

    products = " + ".join(["%f * %s#%s" % (v, m.name, m.id) for m, v in products])
    reactants = " + ".join(["%f * %s#%s" % (-v, m.name, m.id) for m, v in reactants])
    return reactants + " <=> " + products<|endoftext|>


<commit_before>import numpy as np
import pandas as pd
from skimage.measure import regionprops

def ComputeMorphometryFeatures(im_label):
    """
    Calculates morphometry features for each object

    Parameters
    ----------
    im_label : array_like
        A labeled mask image wherein intensity of a pixel is the ID of the
        object it belongs to. Non-zero values are considered to be foreground
        objects.

    rprops[i] : property
        A rprops[i] property from regioprops.

    Returns
    -------
    fdata: Pandas data frame containing the following morphometry features
    for each object/label
        'Area',
        'Circularity',
        'Eccentricity',
        'EquivalentDiameter'
        'Extent',
        'MajorAxisLength',
        'MinorAxisLength',
        'MajorMinorAxisRatio',
        'Perimeter',
        'Solidity',
    """

    # feature names listed in alphabetical order
    feature_list = [
        'Area',
        'Circularity',
        'Eccentricity',
        'EquivalentDiameter'
        'Extent',
        'MajorAxisLength',
        'MinorAxisLength',
        'MajorMinorAxisRatio',
        'Perimeter',
        'Solidity',
    ]

    rprops = regionprops(im_label)

    numFeatures = len(feature_list)
    numLabels = len(rprops)
    fdata = pd.DataFrame(np.zeros(numLabels, numFeatures),
                         columns=feature_list)

    for i in range(numLabels):

        # compute Area
        fdata.at[i, 'Area'] = rprops[i].area

        # compute Circularity
        numerator = 4 * np.pi * rprops[i].Area
        denominator = rprops[i].perimeter**2
        if denominator:
            fdata.at[i, 'Circularity'] = numerator / denominator
        else:
            fdata.at[i, 'Circularity'] = 0  # should this be NaN?

        # compute Eccentricity
        fdata.at[i, 'Eccentricity'] = rprops[i].eccentricity

        # compute EquivalentDiameter
        fdata.at[i, 'EquivalentDiameter'] = rprops[i].equivalent_diameter

        # compute Extent
        fdata.at[i, 'Extent'] = rprops[i].extent

        # compute MajorAxisLength and MinorAxisLength
        fdata.at[i, 'MajorAxisLength'] = rprops[i].major_axis_length
        fdata.at[i, 'MinorAxisLength'] = rprops[i].minor_axis_length

        # compute MajorMinor axis ratios
        fdata.at[i, 'MajorMinorAxisRatio'] = \
            rprops[i].major_axis_length / rprops[i].minor_axis_length

        # compute Perimeter
        fdata.at[i, 'Perimeter'] = rprops[i].perimeter

        # compute Solidity
        fdata.at[i, 'Solidity'] = rprops[i].solidity

    return fdata
<commit_msg>Enhance docstring of ComputeMorphometryFeatures<commit_after>import numpy as np
import pandas as pd
from skimage.measure import regionprops

def ComputeMorphometryFeatures(im_label):
    """
    Calculates morphometry features for each object

    Parameters
    ----------
    im_label : array_like
        A labeled mask image wherein intensity of a pixel is the ID of the
        object it belongs to. Non-zero values are considered to be foreground
        objects.

    rprops[i] : property
        A rprops[i] property from regioprops.

    Returns
    -------
    fdata: pandas.DataFrame
        A pandas dataframe containing the morphometry features for each
        object/label listed below.

    Notes
    -----

    List of morphometry features computed by this function:
    - 'Area',
    - 'Circularity',
    - 'Eccentricity',
    - 'EquivalentDiameter'
    - 'Extent',
    - 'MajorAxisLength',
    - 'MinorAxisLength',
    - 'MajorMinorAxisRatio',
    - 'Perimeter',
    - 'Solidity',
    """

    # feature names listed in alphabetical order
    feature_list = [
        'Area',
        'Circularity',
        'Eccentricity',
        'EquivalentDiameter'
        'Extent',
        'MajorAxisLength',
        'MinorAxisLength',
        'MajorMinorAxisRatio',
        'Perimeter',
        'Solidity',
    ]

    rprops = regionprops(im_label)

    numFeatures = len(feature_list)
    numLabels = len(rprops)
    fdata = pd.DataFrame(np.zeros(numLabels, numFeatures),
                         columns=feature_list)

    for i in range(numLabels):

        # compute Area
        fdata.at[i, 'Area'] = rprops[i].area

        # compute Circularity
        numerator = 4 * np.pi * rprops[i].Area
        denominator = rprops[i].perimeter**2
        if denominator:
            fdata.at[i, 'Circularity'] = numerator / denominator
        else:
            fdata.at[i, 'Circularity'] = 0  # should this be NaN?

        # compute Eccentricity
        fdata.at[i, 'Eccentricity'] = rprops[i].eccentricity

        # compute EquivalentDiameter
        fdata.at[i, 'EquivalentDiameter'] = rprops[i].equivalent_diameter

        # compute Extent
        fdata.at[i, 'Extent'] = rprops[i].extent

        # compute MajorAxisLength and MinorAxisLength
        fdata.at[i, 'MajorAxisLength'] = rprops[i].major_axis_length
        fdata.at[i, 'MinorAxisLength'] = rprops[i].minor_axis_length

        # compute MajorMinor axis ratios
        fdata.at[i, 'MajorMinorAxisRatio'] = \
            rprops[i].major_axis_length / rprops[i].minor_axis_length

        # compute Perimeter
        fdata.at[i, 'Perimeter'] = rprops[i].perimeter

        # compute Solidity
        fdata.at[i, 'Solidity'] = rprops[i].solidity

    return fdata
<|endoftext|>


<commit_before>""" Implements simple keplerian orbital elements calculations. """

import numpy as np
from astropy import units as uts
from astropy import constants as cts

# declare astronomical constants in appropriate units
mu_Earth = cts.GM_earth.to(uts.Unit('km3 / s2')).value

def keplers_equation_by_newtons_method(eccentricity, mean_anomaly, etol=1.e-8):

    E_eccentric_anomaly = mean_anomaly - eccentricity / 2.0
    if mean_anomaly < np.pi:
        E_eccentric_anomaly = mean_anomaly + eccentricity / 2.0

    ratio = 1.0
    while np.abs(ratio) > etol:
        ratio = (E_eccentric_anomaly - eccentricity * np.sin(E_eccentric_anomaly) - mean_anomaly) / (1.0 - eccentricity * np.cos(E_eccentric_anomaly))
        E_eccentric_anomaly = E_eccentric_anomaly - ratio

    return E_eccentric_anomaly

def zeroTo360(x, deg=True):

    if deg == True:
        base = 360.0
    else:
        base = 2.0 * np.pi

    if x >= base:
        x = x - int(x/base) * base

    elif x < 0.0:
        x = x - (int(x/base) - 1.0) * base

    return x

def v_radial(R, V):

    r_abs = np.linalg.norm(R)
    v_radial = np.dot(R, V) / r_abs

    return v_radial

def h_angularmomentuum(R=None, V=None, semimajor_axis=None, eccentricity=None):

    h_angularmomentuum = None

    if R != None and V != None:
        h = np.cross(R, V)
        h_angularmomentuum = np.linalg.norm(h)

    if semimajor_axis != None and eccentricity != None:
        h_angularmomentuum = (semimajor_axis * mu_Earth * (1.0 - eccentricity**2))**0.5

    return h_angularmomentuum

def inclination(R, V):

    h = np.cross(R, V)
    h_angularmomentuum_abs = h_angularmomentuum(R=R, V=V)

    inclination = np.arccos(h[2] / h_angularmomentuum_abs)

    return inclination

def raan(R, V):

    h = np.cross(R, V)

    node_line = np.cross([0.0, 0.0, 1.0], h)
    node_line_abs = np.linalg.norm(node_line)

    raan = np.arccos(node_line[0] / node_line_abs)

    if node_line[1] < 0.0:
        raan = 2.0 * np.pi - raan

    return raan

def eccentricity_v(R, V):
    r_abs = np.linalg.norm(R)
    v_abs = np.linalg.norm(V)

    v_radial = np.dot(R, V) / r_abs

    eccentricity_vec = 1.0 / mu_Earth * ((v_abs ** 2 - mu_Earth / r_abs) * R - r_abs * v_radial * V)

    return eccentricity_vec

def AoP(R, V):

    h = np.cross(R, V)

    node_line = np.cross([0.0, 0.0, 1.0], h)
    node_line_abs = np.linalg.norm(node_line)

    eccentricity_vec = eccentricity_v(R, V)
    eccentricity = np.linalg.norm(eccentricity_vec)

    AoP = np.arccos(np.dot(node_line / node_line_abs, eccentricity_vec / eccentricity))

    if eccentricity_vec[2] < 0.0:
        AoP = 2.0 * np.pi - AoP

    return AoP

def true_anomaly(R=None, V=None, eccentricity=None, E_eccentric_anomaly=None):

    true_anomaly = None

    if R != R and V != V:

        r_abs = np.linalg.norm(R)
        v_abs = np.linalg.norm(V)

        v_radial = np.dot(R, V) / r_abs

        eccentricity_vec = eccentricity_v(R, V)
        eccentricity = np.linalg.norm(eccentricity_vec)

        true_anomaly = np.arccos(np.dot(eccentricity_vec / eccentricity, R / r_abs))

        if v_radial < 0.0:
            true_anomaly = 2.0 * np.pi - true_anomaly

    if eccentricity != None and E_eccentric_anomaly != None:
        true_anomaly = 2.0 * np.arctan(((1.0 + eccentricity) / (1.0 - eccentricity)) ** 0.5 *
                                       np.tan(E_eccentric_anomaly / 2.0))

        true_anomaly = zeroTo360(true_anomaly, deg=False)

    return true_anomaly

def E_eccentric_anomaly(eccentricity=None, true_anomaly=None, mean_anomaly=None):

    E_eccentric_anomaly = None

    if eccentricity != None and true_anomaly != None:
        E_eccentric_anomaly = 2.0 * np.arctan(((1.0 - eccentricity) / (1.0 + eccentricity)) ** 0.5
                                              * np.tan(true_anomaly / 2.0))

    if eccentricity != None and mean_anomaly != None:
        E_eccentric_anomaly = keplers_equation_by_newtons_method(eccentricity, mean_anomaly)

    return E_eccentric_anomaly

def mean_anomaly(E_eccentric_anomaly, eccentricity, true_anomaly):

    mean_anomaly = E_eccentric_anomaly - eccentricity * np.sin(E_eccentric_anomaly)

    if eccentricity > 1.0:
        # if hyperbola
        F_hyp_eccentric_anomaly = 2.0 * np.arctanh(((eccentricity - 1.0) / (eccentricity + 1.0)) ** 0.5
                                                   * np.tan(true_anomaly / 2.0))

        mean_anomaly = eccentricity * np.sinh(F_hyp_eccentric_anomaly) - F_hyp_eccentric_anomaly

    mean_anomaly = zeroTo360(mean_anomaly, deg=False)

    return mean_anomaly

def T_orbitperiod(h_angularmomentuum = None, eccentricity = None, semimajor_axis = None):

    if h_angularmomentuum != None and eccentricity != None:
        T_orbitperiod = 2.0 * np.pi / mu_Earth ** 2 * (h_angularmomentuum / np.sqrt(1 - eccentricity ** 2)) ** 3

    if semimajor_axis != None:
        T_orbitperiod = 2.0 * np.pi / mu_Earth ** 0.5 * semimajor_axis ** (3.0/2.0)

    return T_orbitperiod

def semimajor_axis(R = None, V = None, T_orbitperiod = None):

    semimajor_axis = None

    if R != None and V != None:
        eccentricity_vec = eccentricity_v(R, V)
        eccentricity = np.linalg.norm(eccentricity_vec)

        h_abs = h_angularmomentuum(R=R, V=V)

        semimajor_axis = h_abs ** 2 / mu_Earth * 1.0 / (1.0 - eccentricity ** 2)

        if eccentricity > 1.0:
            # if hyperbola
            semimajor_axis = h_abs ** 2 / mu_Earth * 1.0 / (eccentricity ** 2 - 1.0)

    if T_orbitperiod != None:
        semimajor_axis = (T_orbitperiod * mu_Earth ** 0.5 / (2.0 * np.pi)) ** (2.0 / 3.0)

    return semimajor_axis

def t_since_perige(mean_anomaly, T_orbitperiod):

    t_since_perige = mean_anomaly / (2.0 * np.pi) * T_orbitperiod

    return t_since_perige

def p_orbitparameter(h_angularmomentuum):

    return h_angularmomentuum ** 2 / mu_Earth

def n_mean_motion(T_orbitperiod):

    return (2.0 * np.pi) / T_orbitperiod

def n_mean_motion_perday(T_orbitperiod):

    return 24.0 * 3600.0 / T_orbitperiod

class orbital_parameters:

    # The init method or constructor
    def __init__(self):

        self.AoP = 0.0
        self.true_anomaly = 0.0
        self.raan = 0.0
        self.eccentricity = 0.0
        self.mean_anomaly = 0.0
        self.T_orbitperiod = 0.0
        self.t_since_perigee = 0.0
        self.n_mean_motion = 0.0
        self.n_mean_motion_perday = 0.0
        self.semimajor_axis = 0.0
        self.p_orbitparameter = 0.0
        self.inclination = 0.0
        self.h_angularmomentuum = 0.0
        self.v_radial = 0.0
        self.E_eccentric_anomaly = 0.0

    def get_orbital_elemts_from_statevector(self, R, V):
        '''
        OMFES (4th), H.D.Curtis, p.191, ALGORITHM 4.2

        :param R: position vector of satellite [km]
        :param V: velocity vector of satellite [km/s
        :return:
        '''

        # todo: if other body, this shall be changed
        mu = mu_Earth

        self.v_radial = v_radial(R, V)

        self.h_angularmomentuum = h_angularmomentuum(R, V)

        self.inclination = inclination(R, V)

        self.raan = raan(R, V)

        eccentricity_vec = eccentricity_v(R, V)
        self.eccentricity = np.linalg.norm(eccentricity_vec)

        self.AoP = AoP(R, V)

        self.true_anomaly = true_anomaly(R=R, V=V)

        self.E_eccentric_anomaly = E_eccentric_anomaly(self.eccentricity, self.true_anomaly)

        self.mean_anomaly = mean_anomaly(self.E_eccentric_anomaly, self.eccentricity, self.true_anomaly)

        self.T_orbitperiod = T_orbitperiod(self.h_angularmomentuum, self.eccentricity)

        self.t_since_perigee = t_since_perige(self.mean_anomaly, self.T_orbitperiod)

        self.n_mean_motion = n_mean_motion(self.T_orbitperiod)
        self.n_mean_motion_perday = n_mean_motion_perday(self.T_orbitperiod)

        self.semimajor_axis = semimajor_axis(R, V)

        self.p_orbitparameter = p_orbitparameter(self.h_angularmomentuum)

if __name__ == "__main__":
    '''
            OMFES (4th), H.D.Curtis, p.210, ALGORITHM 4.5

            :param R: position vector of satellite [km]
            :param V: velocity vector of satellite [km/s
            :return:
            '''

    line1 = "1 47856U 21020C   21331.06251800 -.00000072  00000-0  30707-4 0  9998"
    line2 = "2 47856  63.4086 209.7279 0025693 342.6358  17.3780 13.45215752 34829"

    epoch = 331.06251800
    i = 63.4086
    raan = 209.7279
    e = 0.0025693
    aop = 342.6358
    Me = 17.3780
    n = 13.45215752

    T_period = (24.0 * 3600.0) / n
    a = semimajor_axis(T_orbitperiod=T_period)
    h = h_angularmomentuum(semimajor_axis=a, eccentricity=e)
    E = E_eccentric_anomaly(eccentricity=e, mean_anomaly=Me * np.pi/180.0)
    true = true_anomaly(eccentricity=e, E_eccentric_anomaly=E) * 180. / np.pi

    # p. 211
    R = h**2 / (mu_Earth) * 1.0 / (1 + e * np.cos(true * np.pi / 180.0))
    R = R * np.array([np.cos(true * np.pi / 180.0), np.sin(true * np.pi / 180.0), 0.0])

    i = i*np.pi/180
    raan = raan*np.pi/180
    aop = aop*np.pi/180

    Q_Xx = np.array([[+np.cos(aop), np.sin(aop), 0.0],
                     [-np.sin(aop), np.cos(aop), 0.0],
                     [0.0, 0.0, 1.0]])
    Q_Xx = np.dot(Q_Xx,
                       np.array([[1.0, 0.0, 0.0],
                                 [0.0, +np.cos(i), np.sin(i)],
                                 [0.0, -np.sin(i), np.cos(i)]]))
    Q_Xx = np.dot(Q_Xx,
                       np.array([[+np.cos(raan), np.sin(raan), 0.0],
                                 [-np.sin(raan), np.cos(raan), 0.0],
                                 [0.0, 0.0, 1.0]]))

    Q_xX = np.transpose(Q_Xx)
    R = np.array([6285.,3628.6,0.0])
    r = np.dot(R, Q_Xx)<commit_msg>Update orbital_elements.py<commit_after>""" Implements simple keplerian orbital elements calculations. """

import numpy as np
from astropy import units as uts
from astropy import constants as cts

# declare astronomical constants in appropriate units
mu_Earth = cts.GM_earth.to(uts.Unit('km3 / s2')).value

def keplers_equation_by_newtons_method(eccentricity, mean_anomaly, etol=1.e-8):

    E_eccentric_anomaly = mean_anomaly - eccentricity / 2.0
    if mean_anomaly < np.pi:
        E_eccentric_anomaly = mean_anomaly + eccentricity / 2.0

    ratio = 1.0
    while np.abs(ratio) > etol:
        ratio = (E_eccentric_anomaly - eccentricity * np.sin(E_eccentric_anomaly) - mean_anomaly) / (1.0 - eccentricity * np.cos(E_eccentric_anomaly))
        E_eccentric_anomaly = E_eccentric_anomaly - ratio

    return E_eccentric_anomaly

def zeroTo360(x, deg=True):

    if deg == True:
        base = 360.0
    else:
        base = 2.0 * np.pi

    if x >= base:
        x = x - int(x/base) * base

    elif x < 0.0:
        x = x - (int(x/base) - 1.0) * base

    return x

def v_radial(R, V):

    r_abs = np.linalg.norm(R)
    v_radial = np.dot(R, V) / r_abs

    return v_radial

def h_angularmomentuum(R=None, V=None, semimajor_axis=None, eccentricity=None):

    h_angularmomentuum = None

    if R != None and V != None:
        h = np.cross(R, V)
        h_angularmomentuum = np.linalg.norm(h)

    if semimajor_axis != None and eccentricity != None:
        h_angularmomentuum = (semimajor_axis * mu_Earth * (1.0 - eccentricity**2))**0.5

    return h_angularmomentuum

def inclination(R, V):

    h = np.cross(R, V)
    h_angularmomentuum_abs = h_angularmomentuum(R=R, V=V)

    inclination = np.arccos(h[2] / h_angularmomentuum_abs)

    return inclination

def raan(R, V):

    h = np.cross(R, V)

    node_line = np.cross([0.0, 0.0, 1.0], h)
    node_line_abs = np.linalg.norm(node_line)

    raan = np.arccos(node_line[0] / node_line_abs)

    if node_line[1] < 0.0:
        raan = 2.0 * np.pi - raan

    return raan

def eccentricity_v(R, V):
    r_abs = np.linalg.norm(R)
    v_abs = np.linalg.norm(V)

    v_radial = np.dot(R, V) / r_abs

    eccentricity_vec = 1.0 / mu_Earth * ((v_abs ** 2 - mu_Earth / r_abs) * R - r_abs * v_radial * V)

    return eccentricity_vec

def AoP(R, V):

    h = np.cross(R, V)

    node_line = np.cross([0.0, 0.0, 1.0], h)
    node_line_abs = np.linalg.norm(node_line)

    eccentricity_vec = eccentricity_v(R, V)
    eccentricity = np.linalg.norm(eccentricity_vec)

    AoP = np.arccos(np.dot(node_line / node_line_abs, eccentricity_vec / eccentricity))

    if eccentricity_vec[2] < 0.0:
        AoP = 2.0 * np.pi - AoP

    return AoP

def true_anomaly(R=None, V=None, eccentricity=None, E_eccentric_anomaly=None):

    true_anomaly = None

    if R != R and V != V:

        r_abs = np.linalg.norm(R)
        v_abs = np.linalg.norm(V)

        v_radial = np.dot(R, V) / r_abs

        eccentricity_vec = eccentricity_v(R, V)
        eccentricity = np.linalg.norm(eccentricity_vec)

        true_anomaly = np.arccos(np.dot(eccentricity_vec / eccentricity, R / r_abs))

        if v_radial < 0.0:
            true_anomaly = 2.0 * np.pi - true_anomaly

    if eccentricity != None and E_eccentric_anomaly != None:
        true_anomaly = 2.0 * np.arctan(((1.0 + eccentricity) / (1.0 - eccentricity)) ** 0.5 *
                                       np.tan(E_eccentric_anomaly / 2.0))

        true_anomaly = zeroTo360(true_anomaly, deg=False)

    return true_anomaly

def E_eccentric_anomaly(eccentricity=None, true_anomaly=None, mean_anomaly=None):

    E_eccentric_anomaly = None

    if eccentricity != None and true_anomaly != None:
        E_eccentric_anomaly = 2.0 * np.arctan(((1.0 - eccentricity) / (1.0 + eccentricity)) ** 0.5
                                              * np.tan(true_anomaly / 2.0))

    if eccentricity != None and mean_anomaly != None:
        E_eccentric_anomaly = keplers_equation_by_newtons_method(eccentricity, mean_anomaly)

    return E_eccentric_anomaly

def mean_anomaly(E_eccentric_anomaly, eccentricity, true_anomaly):

    mean_anomaly = E_eccentric_anomaly - eccentricity * np.sin(E_eccentric_anomaly)

    if eccentricity > 1.0:
        # if hyperbola
        F_hyp_eccentric_anomaly = 2.0 * np.arctanh(((eccentricity - 1.0) / (eccentricity + 1.0)) ** 0.5
                                                   * np.tan(true_anomaly / 2.0))

        mean_anomaly = eccentricity * np.sinh(F_hyp_eccentric_anomaly) - F_hyp_eccentric_anomaly

    mean_anomaly = zeroTo360(mean_anomaly, deg=False)

    return mean_anomaly

def T_orbitperiod(h_angularmomentuum = None, eccentricity = None, semimajor_axis = None, n_mean_motion_perday=None):

    T_orbitperiod = None

    if h_angularmomentuum != None and eccentricity != None:
        T_orbitperiod = 2.0 * np.pi / mu_Earth ** 2 * (h_angularmomentuum / np.sqrt(1 - eccentricity ** 2)) ** 3

    if semimajor_axis != None:
        T_orbitperiod = 2.0 * np.pi / mu_Earth ** 0.5 * semimajor_axis ** (3.0/2.0)

    if n_mean_motion_perday != None:
        T_orbitperiod = (24.0 * 3600.0) / n_mean_motion_perday

    return T_orbitperiod

def semimajor_axis(R = None, V = None, T_orbitperiod = None):

    semimajor_axis = None

    if R != None and V != None:
        eccentricity_vec = eccentricity_v(R, V)
        eccentricity = np.linalg.norm(eccentricity_vec)

        h_abs = h_angularmomentuum(R=R, V=V)

        semimajor_axis = h_abs ** 2 / mu_Earth * 1.0 / (1.0 - eccentricity ** 2)

        if eccentricity > 1.0:
            # if hyperbola
            semimajor_axis = h_abs ** 2 / mu_Earth * 1.0 / (eccentricity ** 2 - 1.0)

    if T_orbitperiod != None:
        semimajor_axis = (T_orbitperiod * mu_Earth ** 0.5 / (2.0 * np.pi)) ** (2.0 / 3.0)

    return semimajor_axis

def t_since_perige(mean_anomaly, T_orbitperiod):

    t_since_perige = mean_anomaly / (2.0 * np.pi) * T_orbitperiod

    return t_since_perige

def p_orbitparameter(h_angularmomentuum):

    return h_angularmomentuum ** 2 / mu_Earth

def n_mean_motion(T_orbitperiod):

    return (2.0 * np.pi) / T_orbitperiod

def n_mean_motion_perday(T_orbitperiod):

    return 24.0 * 3600.0 / T_orbitperiod

class orbital_parameters:

    # The init method or constructor
    def __init__(self):

        self.AoP = 0.0
        self.true_anomaly = 0.0
        self.raan = 0.0
        self.eccentricity = 0.0
        self.mean_anomaly = 0.0
        self.T_orbitperiod = 0.0
        self.t_since_perigee = 0.0
        self.n_mean_motion = 0.0
        self.n_mean_motion_perday = 0.0
        self.semimajor_axis = 0.0
        self.p_orbitparameter = 0.0
        self.inclination = 0.0
        self.h_angularmomentuum = 0.0
        self.v_radial = 0.0
        self.E_eccentric_anomaly = 0.0

    def get_orbital_elemts_from_statevector(self, R, V):
        '''
        OMFES (4th), H.D.Curtis, p.191, ALGORITHM 4.2

        :param R: position vector of satellite [km]
        :param V: velocity vector of satellite [km/s
        :return:
        '''

        # todo: if other body, this shall be changed
        mu = mu_Earth

        self.v_radial = v_radial(R, V)

        self.h_angularmomentuum = h_angularmomentuum(R, V)

        self.inclination = inclination(R, V)

        self.raan = raan(R, V)

        eccentricity_vec = eccentricity_v(R, V)
        self.eccentricity = np.linalg.norm(eccentricity_vec)

        self.AoP = AoP(R, V)

        self.true_anomaly = true_anomaly(R=R, V=V)

        self.E_eccentric_anomaly = E_eccentric_anomaly(self.eccentricity, self.true_anomaly)

        self.mean_anomaly = mean_anomaly(self.E_eccentric_anomaly, self.eccentricity, self.true_anomaly)

        self.T_orbitperiod = T_orbitperiod(self.h_angularmomentuum, self.eccentricity)

        self.t_since_perigee = t_since_perige(self.mean_anomaly, self.T_orbitperiod)

        self.n_mean_motion = n_mean_motion(self.T_orbitperiod)
        self.n_mean_motion_perday = n_mean_motion_perday(self.T_orbitperiod)

        self.semimajor_axis = semimajor_axis(R, V)

        self.p_orbitparameter = p_orbitparameter(self.h_angularmomentuum)

    def get_statevector_from_orbital_elemts(self, inclination, raan, eccentricity,
                                            AoP, mean_anomaly, n_mean_motion_perday):

        self.inclination = inclination
        self.raan = raan
        self.eccentricity = eccentricity
        self.AoP = AoP
        self.mean_anomaly = mean_anomaly
        self.n_mean_motion_perday = n_mean_motion_perday

        self.T_orbitperiod = T_orbitperiod(n_mean_motion_perday = self.n_mean_motion_perday)
        self.semimajor_axis = semimajor_axis(T_orbitperiod=self.T_orbitperiod)
        self.h_angularmomentuum = h_angularmomentuum(semimajor_axis=self.semimajor_axis, eccentricity=self.eccentricity)
        self.E_eccentric_anomaly = E_eccentric_anomaly(eccentricity=self.eccentricity,
                                                       mean_anomaly=self.mean_anomaly * np.pi / 180.0)
        self.true_anomaly = true_anomaly(eccentricity=self.eccentricity, E_eccentric_anomaly=self.E_eccentric_anomaly) * 180. / np.pi

        # p. 211
        R = self.h_angularmomentuum ** 2 / (mu_Earth) * \
            1.0 / (1 + self.eccentricity * np.cos(self.true_anomaly * np.pi / 180.0))
        R = R * np.array([np.cos(self.true_anomaly * np.pi / 180.0), np.sin(self.true_anomaly * np.pi / 180.0), 0.0])

        inc = self.inclination * np.pi / 180
        raan = self.raan * np.pi / 180
        aop = self.AoP * np.pi / 180

        Q_Xx = np.array([[+np.cos(aop), np.sin(aop), 0.0],
                         [-np.sin(aop), np.cos(aop), 0.0],
                         [0.0, 0.0, 1.0]])
        Q_Xx = np.dot(Q_Xx,
                      np.array([[1.0, 0.0, 0.0],
                                [0.0, +np.cos(inc), np.sin(inc)],
                                [0.0, -np.sin(inc), np.cos(inc)]]))
        Q_Xx = np.dot(Q_Xx,
                      np.array([[+np.cos(raan), np.sin(raan), 0.0],
                                [-np.sin(raan), np.cos(raan), 0.0],
                                [0.0, 0.0, 1.0]]))

        # Q_xX = np.transpose(Q_Xx)
        r = np.dot(R, Q_Xx)

        return r

if __name__ == "__main__":
    '''
            OMFES (4th), H.D.Curtis, p.210, ALGORITHM 4.5

            :param R: position vector of satellite [km]
            :param V: velocity vector of satellite [km/s
            :return:
            '''

    from astropy.time import Time
    from skyfield.api import load, wgs84
    from skyfield.api import EarthSatellite
    import time

    line1 = "1 47856U 21020C   21331.00000000 -.00000072  00000-0  30707-4 0  9998"
    line2 = "2 47856  63.4086 209.7279 0025693 342.6358  17.3780 13.45215752 34829"

    inclination = 63.4086
    raan = 209.7279
    eccentricity = 0.0025693
    AoP = 342.6358
    mean_anomaly = 17.3780
    n_mean_motion_perday = 13.45215752

    epoch = 21331.00000000 #2021-11-27T00:00:00

    observing_time = Time("2021-11-27T00:00:00", format="isot", scale="utc")
    ts = load.timescale()
    t = ts.from_astropy(observing_time)
    satellite = EarthSatellite(line1, line2, 'TEST', ts)
    R1 = satellite.at(t).position.km
    print(R1, np.linalg.norm(R1))

    oe = orbital_parameters()
    R2 = oe.get_statevector_from_orbital_elemts(inclination, raan, eccentricity,
                                                AoP, mean_anomaly, n_mean_motion_perday)
    print(R2, np.linalg.norm(R2))<|endoftext|>


<commit_before># -*- coding: UTF-8 -*-
import datetime
import os.path
from django.conf import settings
from django.db import models
from django.db.models.signals import post_save

import tagging
from tagging.fields import TagField

import conference
import subprocess

class DeadlineManager(models.Manager):
    def valid_news(self):
        today = datetime.date.today()
        return self.all().filter(date__gte = today)

class Deadline(models.Model):
    """
    deadline per il pycon
    """
    date = models.DateField()

    objects = DeadlineManager()

    def __unicode__(self):
        return "deadline: %s" % (self.date, )

    class Meta:
        ordering = ['date']

    def isExpired(self):
       today = datetime.date.today()
       return today > self.date

class DeadlineContent(models.Model):
    """
    Testo, multilingua, di una deadline
    """
    deadline = models.ForeignKey(Deadline)
    language = models.CharField(max_length = 3)
    body = models.TextField()

from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic

class MultilingualContent(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    language = models.CharField(max_length = 3)
    content = models.CharField(max_length = 20)
    body = models.TextField()

import urlparse
from django.core.files.storage import FileSystemStorage

# definisco uno storage custom perché non uso MEDIA_DIR per memorizzare la
# roba sotto stuff

def _build_fs_stuff(subdir):
    fs = FileSystemStorage(
        location = os.path.join(settings.STUFF_DIR, subdir),
        base_url = urlparse.urljoin(settings.MEDIA_URL, 'stuff/%s/' % subdir)
    )

    def build_path(instance, filename):
        fname = instance.slug + os.path.splitext(filename)[1].lower()
        fs.delete(fname)
        return fname

    return fs, build_path

fs_speaker, _speaker_image_path = _build_fs_stuff('speaker')

class Speaker(models.Model):
    name = models.CharField('nome e cognome speaker', max_length = 100)
    slug = models.SlugField()
    homepage = models.URLField(verify_exists = False, blank = True)
    activity = models.CharField(max_length = 50, blank = True)
    industry = models.CharField(max_length = 50, blank = True)
    location = models.CharField(max_length = 100, blank = True)
    image = models.ImageField(upload_to = _speaker_image_path, blank = True, storage = fs_speaker)
    bios = generic.GenericRelation(MultilingualContent)

    class Meta:
        ordering = ['name']

    def __unicode__(self):
        return self.name

    @models.permalink
    def get_absolute_url(self):
        return ('conference-speaker', (), { 'slug': self.slug })

TALK_DURATION = (
    (30, '30 minuti'),
    (45, '45 minuti'),
    (60, '60 minuti'),
    (90, '90 minuti'),
)
TALK_LANGUAGES = (
    ('it', 'Italiano'),
    ('en', 'Inglese'),
)

fs_slides, _talk_slides_path = _build_fs_stuff('slides')

class Talk(models.Model):
    title = models.CharField('titolo del talk', max_length = 100)
    slug = models.SlugField()
    speaker = models.ForeignKey(Speaker)
    duration = models.IntegerField(choices = TALK_DURATION)
    language = models.CharField('lingua del talk', max_length = 3, choices = TALK_LANGUAGES)
    abstracts = generic.GenericRelation(MultilingualContent)
    slides = models.FileField(upload_to = _talk_slides_path, blank = True, storage = fs_slides)
    video = models.URLField(verify_exists = False, blank = True)
    tags = TagField()

    def __unicode__(self):
        return self.title

    @models.permalink
    def get_absolute_url(self):
        return ('conference-talk', (), { 'slug': self.slug })

fs_sponsor_logo, _sponsor_logo_path = _build_fs_stuff('sponsor')

class Sponsor(models.Model):
    """
    Attraverso l'elenco di SponsorIncome un'istanza di Sponsor è collegata
    con le informazioni riguardanti tutte le sponsorizzazioni fatte.
    Sempre in SponsorIncome la conferenza è indicata, come in altri posti,
    con una chiave alfanumerica non collegata a nessuna tabella.
    """
    sponsor = models.CharField(max_length = 100, help_text = 'nome dello sponsor')
    slug = models.SlugField()
    url = models.URLField(verify_exists = False, blank = True)
    logo = models.ImageField(
        upload_to = _sponsor_logo_path, blank = True, storage = fs_sponsor_logo,
        help_text = 'Inserire un immagine raster sufficientemente grande da poter essere scalata al bisogno'
    )

    def __unicode__(self):
        return self.sponsor

def postSaveSponsorHandler(sender, **kwargs):
    tool = os.path.join(os.path.dirname(conference.__file__), 'utils', 'resize_image.py')
    null = open('/dev/null')
    p = subprocess.Popen(
        [tool, settings.STUFF_DIR],
        close_fds=True, stdin=null, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    p.communicate()
post_save.connect(postSaveSponsorHandler, sender=Sponsor)

class SponsorIncome(models.Model):
    sponsor = models.ForeignKey(Sponsor)
    conference = models.CharField(max_length = 20)
    income = models.PositiveIntegerField()
    tags = TagField()

    class Meta:
        ordering = ['conference']

class Schedule(models.Model):
    """
    Direttamente dentro lo schedule abbiamo l'indicazione della conferenza,
    una campo alfanumerico libero, e il giorno a cui si riferisce.

    Attraverso le ForeignKey lo schedule è collegato alle track e agli
    eventi.

    Questi ultimi possono essere dei talk o degli eventi "custom", come la
    pyBirra, e sono collegati alle track in modalità "weak", attraverso un
    tagfield.
    """
    conference = models.CharField(help_text = 'nome della conferenza', max_length = 20)
    slug = models.SlugField()
    date = models.DateField()

class Track(models.Model):
    schedule = models.ForeignKey(Schedule)
    track = models.CharField('nome track', max_length = 20)
    title = models.TextField('titolo della track', help_text = 'HTML supportato')
    translate = models.BooleanField(default = False)

    def __unicode__(self):
        return self.track

class Event(models.Model):
    schedule = models.ForeignKey(Schedule)
    talk = models.ForeignKey(Talk, blank = True, null = True)
    custom = models.TextField(blank = True)
    start_time = models.TimeField()
    track = TagField(help_text = 'Inserire uno o più nomi di track, oppure "keynote"')
    sponsor = models.ForeignKey(Sponsor, blank = True, null = True)

    class Meta:
        ordering = ['start_time']

    def __unicode__(self):
        if self.talk:
            return str(self.talk)
        else:
            return self.custom

<commit_msg>aggiunto un campo order alla track<commit_after># -*- coding: UTF-8 -*-
import datetime
import os.path
from django.conf import settings
from django.db import models
from django.db.models.signals import post_save

import tagging
from tagging.fields import TagField

import conference
import subprocess

class DeadlineManager(models.Manager):
    def valid_news(self):
        today = datetime.date.today()
        return self.all().filter(date__gte = today)

class Deadline(models.Model):
    """
    deadline per il pycon
    """
    date = models.DateField()

    objects = DeadlineManager()

    def __unicode__(self):
        return "deadline: %s" % (self.date, )

    class Meta:
        ordering = ['date']

    def isExpired(self):
       today = datetime.date.today()
       return today > self.date

class DeadlineContent(models.Model):
    """
    Testo, multilingua, di una deadline
    """
    deadline = models.ForeignKey(Deadline)
    language = models.CharField(max_length = 3)
    body = models.TextField()

from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic

class MultilingualContent(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    language = models.CharField(max_length = 3)
    content = models.CharField(max_length = 20)
    body = models.TextField()

import urlparse
from django.core.files.storage import FileSystemStorage

# definisco uno storage custom perché non uso MEDIA_DIR per memorizzare la
# roba sotto stuff

def _build_fs_stuff(subdir):
    fs = FileSystemStorage(
        location = os.path.join(settings.STUFF_DIR, subdir),
        base_url = urlparse.urljoin(settings.MEDIA_URL, 'stuff/%s/' % subdir)
    )

    def build_path(instance, filename):
        fname = instance.slug + os.path.splitext(filename)[1].lower()
        fs.delete(fname)
        return fname

    return fs, build_path

fs_speaker, _speaker_image_path = _build_fs_stuff('speaker')

class Speaker(models.Model):
    name = models.CharField('nome e cognome speaker', max_length = 100)
    slug = models.SlugField()
    homepage = models.URLField(verify_exists = False, blank = True)
    activity = models.CharField(max_length = 50, blank = True)
    industry = models.CharField(max_length = 50, blank = True)
    location = models.CharField(max_length = 100, blank = True)
    image = models.ImageField(upload_to = _speaker_image_path, blank = True, storage = fs_speaker)
    bios = generic.GenericRelation(MultilingualContent)

    class Meta:
        ordering = ['name']

    def __unicode__(self):
        return self.name

    @models.permalink
    def get_absolute_url(self):
        return ('conference-speaker', (), { 'slug': self.slug })

TALK_DURATION = (
    (30, '30 minuti'),
    (45, '45 minuti'),
    (60, '60 minuti'),
    (90, '90 minuti'),
)
TALK_LANGUAGES = (
    ('it', 'Italiano'),
    ('en', 'Inglese'),
)

fs_slides, _talk_slides_path = _build_fs_stuff('slides')

class Talk(models.Model):
    title = models.CharField('titolo del talk', max_length = 100)
    slug = models.SlugField()
    speaker = models.ForeignKey(Speaker)
    duration = models.IntegerField(choices = TALK_DURATION)
    language = models.CharField('lingua del talk', max_length = 3, choices = TALK_LANGUAGES)
    abstracts = generic.GenericRelation(MultilingualContent)
    slides = models.FileField(upload_to = _talk_slides_path, blank = True, storage = fs_slides)
    video = models.URLField(verify_exists = False, blank = True)
    tags = TagField()

    def __unicode__(self):
        return self.title

    @models.permalink
    def get_absolute_url(self):
        return ('conference-talk', (), { 'slug': self.slug })

fs_sponsor_logo, _sponsor_logo_path = _build_fs_stuff('sponsor')

class Sponsor(models.Model):
    """
    Attraverso l'elenco di SponsorIncome un'istanza di Sponsor è collegata
    con le informazioni riguardanti tutte le sponsorizzazioni fatte.
    Sempre in SponsorIncome la conferenza è indicata, come in altri posti,
    con una chiave alfanumerica non collegata a nessuna tabella.
    """
    sponsor = models.CharField(max_length = 100, help_text = 'nome dello sponsor')
    slug = models.SlugField()
    url = models.URLField(verify_exists = False, blank = True)
    logo = models.ImageField(
        upload_to = _sponsor_logo_path, blank = True, storage = fs_sponsor_logo,
        help_text = 'Inserire un immagine raster sufficientemente grande da poter essere scalata al bisogno'
    )

    def __unicode__(self):
        return self.sponsor

def postSaveSponsorHandler(sender, **kwargs):
    tool = os.path.join(os.path.dirname(conference.__file__), 'utils', 'resize_image.py')
    null = open('/dev/null')
    p = subprocess.Popen(
        [tool, settings.STUFF_DIR],
        close_fds=True, stdin=null, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    p.communicate()
post_save.connect(postSaveSponsorHandler, sender=Sponsor)

class SponsorIncome(models.Model):
    sponsor = models.ForeignKey(Sponsor)
    conference = models.CharField(max_length = 20)
    income = models.PositiveIntegerField()
    tags = TagField()

    class Meta:
        ordering = ['conference']

class Schedule(models.Model):
    """
    Direttamente dentro lo schedule abbiamo l'indicazione della conferenza,
    una campo alfanumerico libero, e il giorno a cui si riferisce.

    Attraverso le ForeignKey lo schedule è collegato alle track e agli
    eventi.

    Questi ultimi possono essere dei talk o degli eventi "custom", come la
    pyBirra, e sono collegati alle track in modalità "weak", attraverso un
    tagfield.
    """
    conference = models.CharField(help_text = 'nome della conferenza', max_length = 20)
    slug = models.SlugField()
    date = models.DateField()

class Track(models.Model):
    schedule = models.ForeignKey(Schedule)
    track = models.CharField('nome track', max_length = 20)
    title = models.TextField('titolo della track', help_text = 'HTML supportato')
    order = models.PositiveIntegerField('ordine', default = 0)
    translate = models.BooleanField(default = False)

    def __unicode__(self):
        return self.track

class Event(models.Model):
    schedule = models.ForeignKey(Schedule)
    talk = models.ForeignKey(Talk, blank = True, null = True)
    custom = models.TextField(blank = True)
    start_time = models.TimeField()
    track = TagField(help_text = 'Inserire uno o più nomi di track, oppure "keynote"')
    sponsor = models.ForeignKey(Sponsor, blank = True, null = True)

    class Meta:
        ordering = ['start_time']

    def __unicode__(self):
        if self.talk:
            return str(self.talk)
        else:
            return self.custom

<|endoftext|>


<commit_before># -*- coding: utf8 -*-

import signal
import socketserver
import sys
import threading
import time
from urllib.parse import urlparse

from django.conf import settings
from django.core.management.base import BaseCommand

from holonet.core.validation import validate_recipient

class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass

class HolonetAccessPolicyHandler(object):
    def consider(self, params):
        return validate_recipient(params=params)

class PostfixAccessPolicyHandler(socketserver.BaseRequestHandler, HolonetAccessPolicyHandler):
    # Protocol: http://www.postfix.org/SMTPD_POLICY_README.html
    # Access response codes: http://www.postfix.org/access.5.html

    def handle(self):
        """
        Pack and unpack the dicts used by consider to work with the
        postfix access policy checking protocol
        """
        # self.request is the TCP socket connected to the client
        data_list = []
        packet = self.request.recv(1024).decode('utf-8').split("\n")

        while ''.join(packet).strip():
            data_list.extend(packet)
            if data_list and not data_list[-1]:
                break
            packet = self.request.recv(1024).decode('utf-8').split("\n")

        data = filter(lambda line: len(line), data_list)
        if not data:
            return

        params = dict([line.split("=", 1) for line in data])
        response = self.consider(params)

        self.request.sendall(
            "\n".join(['='.join(item) for item in response.items()] + ['\n']).encode('utf-8')
        )

class Command(BaseCommand):

    option_list = BaseCommand.option_list + (

    )
    help = "Start a daemon for verifying access with postfix smtp access policy deligation"
    args = 'None'

    def handle(self, *args, **options):
        parser = urlparse(settings.POLICYSERVICE_URL)
        host = parser.hostname
        port = parser.port

        server = ThreadedTCPServer((host, port), PostfixAccessPolicyHandler)
        server_thread = threading.Thread(target=server.serve_forever)
        server_thread.daemon = True
        server_thread.start()

        def handler(signum, frame):
            if signum == signal.SIGTERM:
                server.shutdown()
                sys.exit(0)
        signal.signal(signal.SIGTERM, handler)

        while True:
            time.sleep(5.0)

if __name__ == '__main__':
    command = Command()
    command.handle()
<commit_msg>Add sigterm on policy handler<commit_after># -*- coding: utf8 -*-

import signal
import socketserver
import sys
import threading
import time
from urllib.parse import urlparse

from django.conf import settings
from django.core.management.base import BaseCommand

from holonet.core.validation import validate_recipient

class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass

class HolonetAccessPolicyHandler(object):
    def consider(self, params):
        return validate_recipient(params=params)

class PostfixAccessPolicyHandler(socketserver.BaseRequestHandler, HolonetAccessPolicyHandler):
    # Protocol: http://www.postfix.org/SMTPD_POLICY_README.html
    # Access response codes: http://www.postfix.org/access.5.html

    def handle(self):
        """
        Pack and unpack the dicts used by consider to work with the
        postfix access policy checking protocol
        """
        # self.request is the TCP socket connected to the client
        data_list = []
        packet = self.request.recv(1024).decode('utf-8').split("\n")

        while ''.join(packet).strip():
            data_list.extend(packet)
            if data_list and not data_list[-1]:
                break
            packet = self.request.recv(1024).decode('utf-8').split("\n")

        data = filter(lambda line: len(line), data_list)
        if not data:
            return

        params = dict([line.split("=", 1) for line in data])
        response = self.consider(params)

        self.request.sendall(
            "\n".join(['='.join(item) for item in response.items()] + ['\n']).encode('utf-8')
        )

class Command(BaseCommand):

    option_list = BaseCommand.option_list + (

    )
    help = "Start a daemon for verifying access with postfix smtp access policy deligation"
    args = 'None'

    def _handle_sigterm(self, signum, frame):
        sys.exit(0)

    def _handle_sigusr1(self, signum, frame):
        self._handle_sigterm(signum, frame)

    def handle(self, *args, **options):
        parser = urlparse(settings.POLICYSERVICE_URL)
        host = parser.hostname
        port = parser.port

        server = ThreadedTCPServer((host, port), PostfixAccessPolicyHandler)
        server_thread = threading.Thread(target=server.serve_forever)
        server_thread.daemon = True
        server_thread.start()

        # Gracefully exit on sigterm.
        signal.signal(signal.SIGTERM, self._handle_sigterm)

        # A SIGUSR1 signals an exit with an autorestart
        signal.signal(signal.SIGUSR1, self._handle_sigusr1)

        # Handle Keyboard Interrupt
        signal.signal(signal.SIGINT, self._handle_sigterm)

        while True:
            time.sleep(5.0)

if __name__ == '__main__':
    command = Command()
    command.handle()
<|endoftext|>