<commit_before>'''
Created on 1 févr. 2014

@author: inso
'''

from ucoinpy.api import bma
from ucoinpy import PROTOCOL_VERSION
from ucoinpy.documents.peer import Peer, Endpoint, BMAEndpoint
from ucoinpy.documents.block import Block
import logging
import time
import inspect

class Community(object):
    '''
    classdocs
    '''
    def __init__(self, currency, peers):
        '''
        A community is a group of nodes using the same currency.
        '''
        self.currency = currency
        self.peers = peers
        self.requests_cache = {}
        self.last_block = None

        # After initializing the community from latest peers,
        # we refresh its peers tree
        found_peers = self.peering()
        for p in found_peers:
            if p.pubkey not in [peer.pubkey for peer in peers]:
                self.peers.append(p)

    @classmethod
    def create(cls, currency, peer):
        return cls(currency, [peer])

    @classmethod
    def load(cls, json_data):
        peers = []

        currency = json_data['currency']

        for data in json_data['peers']:
            endpoint_inline = next(e for e in data['endpoints']
                            if Endpoint.from_inline(e) is not None)
            endpoint = Endpoint.from_inline(endpoint_inline)
            try:
                peering = bma.network.Peering(endpoint.conn_handler())
                peer_data = peering.get()
                peer = Peer.from_signed_raw("{0}{1}\n".format(peer_data['raw'],
                                                  peer_data['signature']))
                peers.append(peer)
            except:
                pass

        community = cls(currency, peers)
        return community

    def name(self):
        return self.currency

    def __eq__(self, other):
        return (other.currency == self.currency)

    def dividend(self):
        ud = self.request(bma.blockchain.UD)
        block_number = ud['result']['blocks'][-1]
        block = self.request(bma.blockchain.Block,
                             req_args={'number': block_number})
        return block['dividend']

    def peering(self):
        peers = []
        peering_data = self.request(bma.network.peering.Peers)
        logging.debug("Peering : {0}".format(peering_data))
        for peer in peering_data:
            logging.debug(peer)
            peers.append(Peer.from_signed_raw("{0}{1}\n".format(peer['value']['raw'],
                                                                peer['value']['signature'])))
        return peers

    def get_block(self, number=None):
        if number is None:
            data = self.request(bma.blockchain.Current)
        else:
            data = self.request(bma.blockchain.Block,
                                req_args={'number': number})

        return Block.from_signed_raw("{0}{1}\n".format(data['raw'],
                                                       data['signature']))

    def members_pubkeys(self):
        '''
        Listing members pubkeys of a community
        '''
        memberships = self.request(bma.wot.Members)
        members = []
        logging.debug(memberships)
        for m in memberships["results"]:
            members.append(m['pubkey'])
        return members

    def request(self, request, req_args={}, get_args={}):
        for peer in self.peers:
            e = next(e for e in peer.endpoints if type(e) is BMAEndpoint)
            # We request the current block every five minutes
            # If a new block is mined we reset the cache
            if self.last_block is None:
                block = bma.blockchain.Current(e.conn_handler()).get()
                self.last_block = {"request_ts": time.time(),
                                   "number": block['number']}
            elif self.last_block["request_ts"] + 60 < time.time():
                logging.debug("{0} > {1}".format(self.last_block["request_ts"] + 60, time.time()))
                self.last_block["request_ts"] = time.time()
                block = bma.blockchain.Current(e.conn_handler()).get()
                if block['number'] > self.last_block['number']:
                    self.last_block["number"] = block['number']
                    self.requests_cache = {}

            cache_key = (hash(request),
                         hash(tuple(frozenset(sorted(req_args.keys())))),
                         hash(tuple(frozenset(sorted(req_args.items())))),
                         hash(tuple(frozenset(sorted(get_args.keys())))),
                         hash(tuple(frozenset(sorted(get_args.items())))))

            if cache_key not in self.requests_cache.keys():
                if e.server:
                    logging.debug("Connecting to {0}:{1}".format(e.server,
                                                             e.port))
                else:
                    logging.debug("Connecting to {0}:{1}".format(e.ipv4,
                                                             e.port))

                req = request(e.conn_handler(), **req_args)
                data = req.get(**get_args)
                if inspect.isgenerator(data):
                    cached_data = []
                    for d in data:
                        cached_data.append(d)
                    self.requests_cache[cache_key] = cached_data
                else:
                    self.requests_cache[cache_key] = data
            return self.requests_cache[cache_key]

    def post(self, request, req_args={}, post_args={}):
        for peer in self.peers:
            e = next(e for e in peer.endpoints if type(e) is BMAEndpoint)
            logging.debug("Trying to connect to : " + peer.pubkey)
            req = request(e.conn_handler(), **req_args)
            try:
                req.post(**post_args)
            except ValueError as e:
                raise
            except:
                pass
            return

    def broadcast(self, request, req_args={}, post_args={}):
        for peer in self.peers:
            e = next(e for e in peer.endpoints if type(e) is BMAEndpoint)
            logging.debug("Trying to connect to : " + peer.pubkey)
            req = request(e.conn_handler(), **req_args)
            try:
                req.post(**post_args)
            except ValueError as e:
                if peer == self.peers[0]:
                    raise
            except:
                pass

    def jsonify_peers_list(self):
        data = []
        for peer in self.peers:
            endpoints_data = []
            for e in peer.endpoints:
                endpoints_data.append(e.inline())
            data.append({'endpoints': endpoints_data,
                         'pubkey': peer.pubkey})
        return data

    def jsonify(self):
        data = {'currency': self.currency,
                'peers': self.jsonify_peers_list()}
        return data

    def get_parameters(self):
        return self.request(bma.blockchain.Parameters)
<commit_msg>Clear nodes not using the same currency from the peers<commit_after>'''
Created on 1 févr. 2014

@author: inso
'''

from ucoinpy.api import bma
from ucoinpy import PROTOCOL_VERSION
from ucoinpy.documents.peer import Peer, Endpoint, BMAEndpoint
from ucoinpy.documents.block import Block
import logging
import time
import inspect

class Community(object):
    '''
    classdocs
    '''
    def __init__(self, currency, peers):
        '''
        A community is a group of nodes using the same currency.
        '''
        self.currency = currency
        self.peers = [p for p in peers if p.currency == currency]
        self.requests_cache = {}
        self.last_block = None

        # After initializing the community from latest peers,
        # we refresh its peers tree
        found_peers = self.peering()
        for p in found_peers:
            logging.debug(p.currency)
            if p.pubkey not in [peer.pubkey for peer in peers]:
                self.peers.append(p)

    @classmethod
    def create(cls, currency, peer):
        return cls(currency, [peer])

    @classmethod
    def load(cls, json_data):
        peers = []

        currency = json_data['currency']

        for data in json_data['peers']:
            endpoint_inline = next(e for e in data['endpoints']
                            if Endpoint.from_inline(e) is not None)
            endpoint = Endpoint.from_inline(endpoint_inline)
            try:
                peering = bma.network.Peering(endpoint.conn_handler())
                peer_data = peering.get()
                peer = Peer.from_signed_raw("{0}{1}\n".format(peer_data['raw'],
                                                  peer_data['signature']))
                peers.append(peer)
            except:
                pass

        community = cls(currency, peers)
        return community

    def name(self):
        return self.currency

    def __eq__(self, other):
        return (other.currency == self.currency)

    def dividend(self):
        ud = self.request(bma.blockchain.UD)
        block_number = ud['result']['blocks'][-1]
        block = self.request(bma.blockchain.Block,
                             req_args={'number': block_number})
        return block['dividend']

    def peering(self):
        peers = []
        peering_data = self.request(bma.network.peering.Peers)
        logging.debug("Peering : {0}".format(peering_data))
        for peer in peering_data:
            logging.debug(peer)
            peers.append(Peer.from_signed_raw("{0}{1}\n".format(peer['value']['raw'],
                                                                peer['value']['signature'])))
        return peers

    def get_block(self, number=None):
        if number is None:
            data = self.request(bma.blockchain.Current)
        else:
            data = self.request(bma.blockchain.Block,
                                req_args={'number': number})

        return Block.from_signed_raw("{0}{1}\n".format(data['raw'],
                                                       data['signature']))

    def members_pubkeys(self):
        '''
        Listing members pubkeys of a community
        '''
        memberships = self.request(bma.wot.Members)
        members = []
        logging.debug(memberships)
        for m in memberships["results"]:
            members.append(m['pubkey'])
        return members

    def request(self, request, req_args={}, get_args={}):
        for peer in self.peers:
            e = next(e for e in peer.endpoints if type(e) is BMAEndpoint)
            # We request the current block every five minutes
            # If a new block is mined we reset the cache
            if self.last_block is None:
                block = bma.blockchain.Current(e.conn_handler()).get()
                self.last_block = {"request_ts": time.time(),
                                   "number": block['number']}
            elif self.last_block["request_ts"] + 60 < time.time():
                logging.debug("{0} > {1}".format(self.last_block["request_ts"] + 60, time.time()))
                self.last_block["request_ts"] = time.time()
                block = bma.blockchain.Current(e.conn_handler()).get()
                if block['number'] > self.last_block['number']:
                    self.last_block["number"] = block['number']
                    self.requests_cache = {}

            cache_key = (hash(request),
                         hash(tuple(frozenset(sorted(req_args.keys())))),
                         hash(tuple(frozenset(sorted(req_args.items())))),
                         hash(tuple(frozenset(sorted(get_args.keys())))),
                         hash(tuple(frozenset(sorted(get_args.items())))))

            if cache_key not in self.requests_cache.keys():
                if e.server:
                    logging.debug("Connecting to {0}:{1}".format(e.server,
                                                             e.port))
                else:
                    logging.debug("Connecting to {0}:{1}".format(e.ipv4,
                                                             e.port))

                req = request(e.conn_handler(), **req_args)
                data = req.get(**get_args)
                if inspect.isgenerator(data):
                    cached_data = []
                    for d in data:
                        cached_data.append(d)
                    self.requests_cache[cache_key] = cached_data
                else:
                    self.requests_cache[cache_key] = data
            return self.requests_cache[cache_key]

    def post(self, request, req_args={}, post_args={}):
        for peer in self.peers:
            e = next(e for e in peer.endpoints if type(e) is BMAEndpoint)
            logging.debug("Trying to connect to : " + peer.pubkey)
            req = request(e.conn_handler(), **req_args)
            try:
                req.post(**post_args)
            except ValueError as e:
                raise
            except:
                pass
            return

    def broadcast(self, request, req_args={}, post_args={}):
        for peer in self.peers:
            e = next(e for e in peer.endpoints if type(e) is BMAEndpoint)
            logging.debug("Trying to connect to : " + peer.pubkey)
            req = request(e.conn_handler(), **req_args)
            try:
                req.post(**post_args)
            except ValueError as e:
                if peer == self.peers[0]:
                    raise
            except:
                pass

    def jsonify_peers_list(self):
        data = []
        for peer in self.peers:
            endpoints_data = []
            for e in peer.endpoints:
                endpoints_data.append(e.inline())
            data.append({'endpoints': endpoints_data,
                         'pubkey': peer.pubkey})
        return data

    def jsonify(self):
        data = {'currency': self.currency,
                'peers': self.jsonify_peers_list()}
        return data

    def get_parameters(self):
        return self.request(bma.blockchain.Parameters)
<|endoftext|>


<commit_before>'''
Created on 1 févr. 2014

@author: inso
'''

from PyQt5.QtCore import QObject, pyqtSignal
from ucoinpy.api import bma
from ucoinpy.documents.block import Block
from ..tools.exceptions import NoPeerAvailable
from .net.node import Node
from .net.network import Network
import logging
import inspect
import hashlib
import re
import time
from requests.exceptions import RequestException

class Cache():
    _saved_requests = [str(bma.blockchain.Block), str(bma.blockchain.Parameters)]

    def __init__(self, community):
        '''
        Init an empty cache
        '''
        self.latest_block = 0
        self.community = community
        self.data = {}

    def load_from_json(self, data):
        '''
        Put data in the cache from json datas.

        :param dict data: The cache in json format
        '''
        self.data = {}
        for entry in data['cache']:
            key = entry['key']
            cache_key = (key[0], key[1], key[2], key[3], key[4])
            self.data[cache_key] = entry['value']

        self.latest_block = data['latest_block']

    def jsonify(self):
        '''
        Get the cache in json format

        :return: The cache as a dict in json format
        '''
        data = {k: self.data[k] for k in self.data.keys()}
        entries = []
        for d in data:
            entries.append({'key': d,
                            'value': data[d]})
        return {'latest_block': self.latest_block,
                'cache': entries}

    def refresh(self):
        '''
        Refreshing the cache just clears every last requests which
        cannot be saved because they can change from one block to another.
        '''
        if self.latest_block < self.community.network.latest_block:
            self.latest_block = self.community.network.latest_block
            self.data = {k: self.data[k] for k in self.data.keys()
                       if k[0] in Cache._saved_requests}

    def request(self, request, req_args={}, get_args={}):
        '''
        Send a cached request to a community.
        If the request was already sent in current block, return last value get.

        :param request: The request bma class
        :param req_args: The arguments passed to the request constructor
        :param get_args: The arguments passed to the requests __get__ method
        '''
        cache_key = (str(request),
                     str(tuple(frozenset(sorted(req_args.keys())))),
                     str(tuple(frozenset(sorted(req_args.items())))),
                     str(tuple(frozenset(sorted(get_args.keys())))),
                     str(tuple(frozenset(sorted(get_args.items())))))

        if cache_key not in self.data.keys():
            result = self.community.request(request, req_args, get_args,
                                         cached=False)

            # Do not cache block 0
            if self.latest_block == 0:
                return result
            else:
                self.data[cache_key] = result
            return self.data[cache_key]
        else:
            return self.data[cache_key]

class Community(QObject):
    '''
    A community is a group of nodes using the same currency.

    .. warning:: The currency name is supposed to be unique in cutecoin
    but nothing exists in ucoin to assert that a currency name is unique.
    '''

    def __init__(self, currency, network):
        '''
        Initialize community attributes with a currency and a network.

        :param str currency: The currency name of the community.
        :param network: The network of the community

        .. warning:: The community object should be created using its factory
        class methods.
        '''
        super().__init__()
        self.currency = currency
        self._network = network
        self._cache = Cache(self)
        self._cache.refresh()

    @classmethod
    def create(cls, node):
        '''
        Create a community from its first node.

        :param node: The first Node of the community
        '''
        network = Network.create(node)
        community = cls(node.currency, network)
        logging.debug("Creating community")
        return community

    @classmethod
    def load(cls, json_data):
        '''
        Load a community from json

        :param dict json_data: The community as a dict in json format
        '''
        currency = json_data['currency']
        network = Network.from_json(currency, json_data['peers'])
        community = cls(currency, network)
        return community

    def load_merge_network(self, json_data):
        '''
        Load the last state of the network.
        This network is merged with the network currently
        known network.

        :param dict json_data:
        '''
        self._network.merge_with_json(json_data)

    def load_cache(self, json_data):
        '''
        Load the community cache.

        :param dict json_data: The community as a dict in json format.
        '''
        self._cache.load_from_json(json_data)

    def jsonify_cache(self):
        '''
        Get the cache jsonified.

        :return: The cache as a dict in json format.
        '''
        return self._cache.jsonify()

    def jsonify_network(self):
        '''
        Get the network jsonified.
        '''
        return self._network.jsonify()

    @property
    def name(self):
        '''
        The community name is its currency name.

        :return: The community name
        '''
        return self.currency

    def __eq__(self, other):
        '''
        :return: True if this community has the same currency name as the other one.
        '''
        return (other.currency == self.currency)

    @property
    def short_currency(self):
        '''
        Format the currency name to a short one

        :return: The currency name in a shot format.
        '''
        words = re.split('[_\W]+', self.currency)
        shortened = ""
        if len(words) > 1:
            shortened = ''.join([w[0] for w in words])
        else:
            vowels = ('a', 'e', 'i', 'o', 'u', 'y')
            shortened = self.currency
            shortened = ''.join([c for c in shortened if c not in vowels])
        return shortened.upper()

    @property
    def currency_symbol(self):
        '''
        Format the currency name to a symbol one.

        :return: The currency name as a utf-8 circled symbol.
        '''
        letter = self.currency[0]
        u = ord('\u24B6') + ord(letter) - ord('A')
        return chr(u)

    @property
    def dividend(self):
        '''
        Get the last generated community universal dividend.

        :return: The last UD or 1 if no UD was generated.
        '''
        block = self.get_ud_block()
        if block:
            return block['dividend']
        else:
            return 1

    def get_ud_block(self, x=0):
        '''
        Get a block with universal dividend

        :param int x: Get the 'x' older block with UD in it
        :return: The last block with universal dividend.
        '''
        blocks = self.request(bma.blockchain.UD)['result']['blocks']
        if len(blocks) > 0:
            block_number = blocks[len(blocks)-(1+x)]
            block = self.request(bma.blockchain.Block,
                                 req_args={'number': block_number})
            return block
        else:
            return False

    @property
    def monetary_mass(self):
        '''
        Get the community monetary mass

        :return: The monetary mass value
        '''
        try:
            block = self.request(bma.blockchain.Current)
            return block['monetaryMass']
        except ValueError as e:
            if '404' in e:
                return 0

    @property
    def nb_members(self):
        '''
        Get the community members number

        :return: The community members number
        '''
        try:
            block = self.request(bma.blockchain.Current)
            return block['membersCount']
        except ValueError as e:
            if '404' in e:
                return 0

    @property
    def network(self):
        '''
        Get the community network instance.

        :return: The community network instance.
        '''
        return self._network

    def network_quality(self):
        '''
        Get a ratio of the synced nodes vs the rest
        '''
        synced = len(self._network.synced_nodes)
        #online = len(self._network.online_nodes)
        total = len(self._network.nodes)
        ratio_synced = synced / total
        return ratio_synced

    @property
    def parameters(self):
        '''
        Return community parameters in bma format
        '''
        return self.request(bma.blockchain.Parameters)

    def certification_expired(self, certtime):
        '''
        Return True if the certificaton time is too old
        '''
        return time.time() - certtime > self.parameters['sigValidity']

    def add_node(self, node):
        '''
        Add a peer to the community.

        :param peer: The new peer as a ucoinpy Peer object.
        '''
        self._network.add_root_node(node)

    def remove_node(self, index):
        '''
        Remove a node from the community.

        :param index: The index of the removed node.
        '''
        self._network.remove_root_node(index)

    def get_block(self, number=None):
        '''
        Get a block

        :param int number: The block number. If none, returns current block.
        '''
        if number is None:
            data = self.request(bma.blockchain.Current)
        else:
            data = self.request(bma.blockchain.Block,
                                req_args={'number': number})

        return Block.from_signed_raw("{0}{1}\n".format(data['raw'],
                                                       data['signature']))

    def current_blockid(self):
        '''
        Get the current block id.

        :return: The current block ID as [NUMBER-HASH] format.
        '''
        try:
            block = self.request(bma.blockchain.Current, cached=False)
            signed_raw = "{0}{1}\n".format(block['raw'], block['signature'])
            block_hash = hashlib.sha1(signed_raw.encode("ascii")).hexdigest().upper()
            block_number = block['number']
        except ValueError as e:
            if '404' in str(e):
                block_number = 0
                block_hash = "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"
            else:
                raise
        return {'number': block_number, 'hash': block_hash}

    def members_pubkeys(self):
        '''
        Listing members pubkeys of a community

        :return: All members pubkeys.
        '''
        memberships = self.request(bma.wot.Members)
        return [m['pubkey'] for m in memberships["results"]]

    def refresh_cache(self):
        '''
        Start the refresh processing of the cache
        '''
        self._cache.refresh()

    def request(self, request, req_args={}, get_args={}, cached=True):
        '''
        Start a request to the community.

        :param request: A ucoinpy bma request class
        :param req_args: Arguments to pass to the request constructor
        :param get_args: Arguments to pass to the request __get__ method
        :return: The returned data
        '''
        if cached:
            return self._cache.request(request, req_args, get_args)
        else:
            nodes = self._network.synced_nodes
            for node in nodes:
                try:
                    req = request(node.endpoint.conn_handler(), **req_args)
                    data = req.get(**get_args)

                    if inspect.isgenerator(data):
                        generated = []
                        for d in data:
                            generated.append(d)
                        return generated
                    else:
                        return data
                except ValueError as e:
                    if '502' in str(e):
                        continue
                    else:
                        raise
                except RequestException as e:
                    logging.debug("Error : {1} : {0}".format(str(e),
                                                             str(request)))
                    continue
        raise NoPeerAvailable(self.currency, len(nodes))

    def post(self, request, req_args={}, post_args={}):
        '''
        Post data to a community.
        Only sends the data to one node.

        :param request: A ucoinpy bma request class
        :param req_args: Arguments to pass to the request constructor
        :param post_args: Arguments to pass to the request __post__ method
        :return: The returned data
        '''
        nodes = self._network.online_nodes
        for node in nodes:
            req = request(node.endpoint.conn_handler(), **req_args)
            logging.debug("Trying to connect to : " + node.pubkey)
            req = request(node.endpoint.conn_handler(), **req_args)
            try:
                req.post(**post_args)
                return
            except ValueError as e:
                raise
            except RequestException:
                continue
        raise NoPeerAvailable(self.currency, len(nodes))

    def broadcast(self, request, req_args={}, post_args={}):
        '''
        Broadcast data to a community.
        Sends the data to all knew nodes.

        :param request: A ucoinpy bma request class
        :param req_args: Arguments to pass to the request constructor
        :param post_args: Arguments to pass to the request __post__ method
        :return: The returned data

        .. note:: If one node accept the requests (returns 200),
        the broadcast is considered accepted by the network.
        '''
        tries = 0
        ok = False
        value_error = None
        nodes = self._network.online_nodes
        for node in nodes:
            logging.debug("Trying to connect to : " + node.pubkey)
            req = request(node.endpoint.conn_handler(), **req_args)
            try:
                req.post(**post_args)
                ok = True
            except ValueError as e:
                value_error = e
                continue
            except RequestException:
                tries = tries + 1
                continue

        if not ok:
            raise value_error

        if tries == len(nodes):
            raise NoPeerAvailable(self.currency, len(nodes))

    def jsonify(self):
        '''
        Jsonify the community datas.

        :return: The community as a dict in json format.
        '''

        nodes_data = []
        for node in self._network.root_nodes:
            nodes_data.append(node.jsonify_root_node())

        data = {'currency': self.currency,
                'peers': nodes_data}
        return data
<commit_msg>Fixing bug when lloading a new account<commit_after>'''
Created on 1 févr. 2014

@author: inso
'''

from PyQt5.QtCore import QObject, pyqtSignal
from ucoinpy.api import bma
from ucoinpy.documents.block import Block
from ..tools.exceptions import NoPeerAvailable
from .net.node import Node
from .net.network import Network
import logging
import inspect
import hashlib
import re
import time
from requests.exceptions import RequestException

class Cache():
    _saved_requests = [str(bma.blockchain.Block), str(bma.blockchain.Parameters)]

    def __init__(self, community):
        '''
        Init an empty cache
        '''
        self.latest_block = 0
        self.community = community
        self.data = {}

    def load_from_json(self, data):
        '''
        Put data in the cache from json datas.

        :param dict data: The cache in json format
        '''
        self.data = {}
        for entry in data['cache']:
            key = entry['key']
            cache_key = (key[0], key[1], key[2], key[3], key[4])
            self.data[cache_key] = entry['value']

        self.latest_block = data['latest_block']

    def jsonify(self):
        '''
        Get the cache in json format

        :return: The cache as a dict in json format
        '''
        data = {k: self.data[k] for k in self.data.keys()}
        entries = []
        for d in data:
            entries.append({'key': d,
                            'value': data[d]})
        return {'latest_block': self.latest_block,
                'cache': entries}

    def refresh(self):
        '''
        Refreshing the cache just clears every last requests which
        cannot be saved because they can change from one block to another.
        '''
        logging.debug("Refresh : {0}/{1}".format(self.latest_block,
                                                 self.community.network.latest_block))
        if self.latest_block < self.community.network.latest_block:
            self.latest_block = self.community.network.latest_block
            self.data = {k: self.data[k] for k in self.data.keys()
                       if k[0] in Cache._saved_requests}

    def request(self, request, req_args={}, get_args={}):
        '''
        Send a cached request to a community.
        If the request was already sent in current block, return last value get.

        :param request: The request bma class
        :param req_args: The arguments passed to the request constructor
        :param get_args: The arguments passed to the requests __get__ method
        '''
        cache_key = (str(request),
                     str(tuple(frozenset(sorted(req_args.keys())))),
                     str(tuple(frozenset(sorted(req_args.items())))),
                     str(tuple(frozenset(sorted(get_args.keys())))),
                     str(tuple(frozenset(sorted(get_args.items())))))

        if cache_key not in self.data.keys():
            result = self.community.request(request, req_args, get_args,
                                         cached=False)

            self.data[cache_key] = result
            return self.data[cache_key]
        else:
            return self.data[cache_key]

class Community(QObject):
    '''
    A community is a group of nodes using the same currency.

    .. warning:: The currency name is supposed to be unique in cutecoin
    but nothing exists in ucoin to assert that a currency name is unique.
    '''

    def __init__(self, currency, network):
        '''
        Initialize community attributes with a currency and a network.

        :param str currency: The currency name of the community.
        :param network: The network of the community

        .. warning:: The community object should be created using its factory
        class methods.
        '''
        super().__init__()
        self.currency = currency
        self._network = network
        self._cache = Cache(self)
        self._cache.refresh()

    @classmethod
    def create(cls, node):
        '''
        Create a community from its first node.

        :param node: The first Node of the community
        '''
        network = Network.create(node)
        community = cls(node.currency, network)
        logging.debug("Creating community")
        return community

    @classmethod
    def load(cls, json_data):
        '''
        Load a community from json

        :param dict json_data: The community as a dict in json format
        '''
        currency = json_data['currency']
        network = Network.from_json(currency, json_data['peers'])
        community = cls(currency, network)
        return community

    def load_merge_network(self, json_data):
        '''
        Load the last state of the network.
        This network is merged with the network currently
        known network.

        :param dict json_data:
        '''
        self._network.merge_with_json(json_data)

    def load_cache(self, json_data):
        '''
        Load the community cache.

        :param dict json_data: The community as a dict in json format.
        '''
        self._cache.load_from_json(json_data)

    def jsonify_cache(self):
        '''
        Get the cache jsonified.

        :return: The cache as a dict in json format.
        '''
        return self._cache.jsonify()

    def jsonify_network(self):
        '''
        Get the network jsonified.
        '''
        return self._network.jsonify()

    @property
    def name(self):
        '''
        The community name is its currency name.

        :return: The community name
        '''
        return self.currency

    def __eq__(self, other):
        '''
        :return: True if this community has the same currency name as the other one.
        '''
        return (other.currency == self.currency)

    @property
    def short_currency(self):
        '''
        Format the currency name to a short one

        :return: The currency name in a shot format.
        '''
        words = re.split('[_\W]+', self.currency)
        shortened = ""
        if len(words) > 1:
            shortened = ''.join([w[0] for w in words])
        else:
            vowels = ('a', 'e', 'i', 'o', 'u', 'y')
            shortened = self.currency
            shortened = ''.join([c for c in shortened if c not in vowels])
        return shortened.upper()

    @property
    def currency_symbol(self):
        '''
        Format the currency name to a symbol one.

        :return: The currency name as a utf-8 circled symbol.
        '''
        letter = self.currency[0]
        u = ord('\u24B6') + ord(letter) - ord('A')
        return chr(u)

    @property
    def dividend(self):
        '''
        Get the last generated community universal dividend.

        :return: The last UD or 1 if no UD was generated.
        '''
        block = self.get_ud_block()
        if block:
            return block['dividend']
        else:
            return 1

    def get_ud_block(self, x=0):
        '''
        Get a block with universal dividend

        :param int x: Get the 'x' older block with UD in it
        :return: The last block with universal dividend.
        '''
        blocks = self.request(bma.blockchain.UD)['result']['blocks']
        if len(blocks) > 0:
            block_number = blocks[len(blocks)-(1+x)]
            block = self.request(bma.blockchain.Block,
                                 req_args={'number': block_number})
            return block
        else:
            return False

    @property
    def monetary_mass(self):
        '''
        Get the community monetary mass

        :return: The monetary mass value
        '''
        try:
            block = self.request(bma.blockchain.Current)
            return block['monetaryMass']
        except ValueError as e:
            if '404' in e:
                return 0

    @property
    def nb_members(self):
        '''
        Get the community members number

        :return: The community members number
        '''
        try:
            block = self.request(bma.blockchain.Current)
            return block['membersCount']
        except ValueError as e:
            if '404' in e:
                return 0

    @property
    def network(self):
        '''
        Get the community network instance.

        :return: The community network instance.
        '''
        return self._network

    def network_quality(self):
        '''
        Get a ratio of the synced nodes vs the rest
        '''
        synced = len(self._network.synced_nodes)
        #online = len(self._network.online_nodes)
        total = len(self._network.nodes)
        ratio_synced = synced / total
        return ratio_synced

    @property
    def parameters(self):
        '''
        Return community parameters in bma format
        '''
        return self.request(bma.blockchain.Parameters)

    def certification_expired(self, certtime):
        '''
        Return True if the certificaton time is too old
        '''
        return time.time() - certtime > self.parameters['sigValidity']

    def add_node(self, node):
        '''
        Add a peer to the community.

        :param peer: The new peer as a ucoinpy Peer object.
        '''
        self._network.add_root_node(node)

    def remove_node(self, index):
        '''
        Remove a node from the community.

        :param index: The index of the removed node.
        '''
        self._network.remove_root_node(index)

    def get_block(self, number=None):
        '''
        Get a block

        :param int number: The block number. If none, returns current block.
        '''
        if number is None:
            data = self.request(bma.blockchain.Current)
        else:
            data = self.request(bma.blockchain.Block,
                                req_args={'number': number})

        return Block.from_signed_raw("{0}{1}\n".format(data['raw'],
                                                       data['signature']))

    def current_blockid(self):
        '''
        Get the current block id.

        :return: The current block ID as [NUMBER-HASH] format.
        '''
        try:
            block = self.request(bma.blockchain.Current, cached=False)
            signed_raw = "{0}{1}\n".format(block['raw'], block['signature'])
            block_hash = hashlib.sha1(signed_raw.encode("ascii")).hexdigest().upper()
            block_number = block['number']
        except ValueError as e:
            if '404' in str(e):
                block_number = 0
                block_hash = "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"
            else:
                raise
        return {'number': block_number, 'hash': block_hash}

    def members_pubkeys(self):
        '''
        Listing members pubkeys of a community

        :return: All members pubkeys.
        '''
        memberships = self.request(bma.wot.Members)
        return [m['pubkey'] for m in memberships["results"]]

    def refresh_cache(self):
        '''
        Start the refresh processing of the cache
        '''
        # We have to refresh node before refresh cache
        self._cache.refresh()

    def request(self, request, req_args={}, get_args={}, cached=True):
        '''
        Start a request to the community.

        :param request: A ucoinpy bma request class
        :param req_args: Arguments to pass to the request constructor
        :param get_args: Arguments to pass to the request __get__ method
        :return: The returned data
        '''
        if cached:
            return self._cache.request(request, req_args, get_args)
        else:
            nodes = self._network.synced_nodes
            for node in nodes:
                try:
                    req = request(node.endpoint.conn_handler(), **req_args)
                    data = req.get(**get_args)

                    if inspect.isgenerator(data):
                        generated = []
                        for d in data:
                            generated.append(d)
                        return generated
                    else:
                        return data
                except ValueError as e:
                    if '502' in str(e):
                        continue
                    else:
                        raise
                except RequestException as e:
                    logging.debug("Error : {1} : {0}".format(str(e),
                                                             str(request)))
                    continue
        raise NoPeerAvailable(self.currency, len(nodes))

    def post(self, request, req_args={}, post_args={}):
        '''
        Post data to a community.
        Only sends the data to one node.

        :param request: A ucoinpy bma request class
        :param req_args: Arguments to pass to the request constructor
        :param post_args: Arguments to pass to the request __post__ method
        :return: The returned data
        '''
        nodes = self._network.online_nodes
        for node in nodes:
            req = request(node.endpoint.conn_handler(), **req_args)
            logging.debug("Trying to connect to : " + node.pubkey)
            req = request(node.endpoint.conn_handler(), **req_args)
            try:
                req.post(**post_args)
                return
            except ValueError as e:
                raise
            except RequestException:
                continue
        raise NoPeerAvailable(self.currency, len(nodes))

    def broadcast(self, request, req_args={}, post_args={}):
        '''
        Broadcast data to a community.
        Sends the data to all knew nodes.

        :param request: A ucoinpy bma request class
        :param req_args: Arguments to pass to the request constructor
        :param post_args: Arguments to pass to the request __post__ method
        :return: The returned data

        .. note:: If one node accept the requests (returns 200),
        the broadcast is considered accepted by the network.
        '''
        tries = 0
        ok = False
        value_error = None
        nodes = self._network.online_nodes
        for node in nodes:
            logging.debug("Trying to connect to : " + node.pubkey)
            req = request(node.endpoint.conn_handler(), **req_args)
            try:
                req.post(**post_args)
                ok = True
            except ValueError as e:
                value_error = e
                continue
            except RequestException:
                tries = tries + 1
                continue

        if not ok:
            raise value_error

        if tries == len(nodes):
            raise NoPeerAvailable(self.currency, len(nodes))

    def jsonify(self):
        '''
        Jsonify the community datas.

        :return: The community as a dict in json format.
        '''

        nodes_data = []
        for node in self._network.root_nodes:
            nodes_data.append(node.jsonify_root_node())

        data = {'currency': self.currency,
                'peers': nodes_data}
        return data
<|endoftext|>


<commit_before>import logging
import email
import sqlite3
import base64
import hashlib
import os

import helper

class mailElement(object):
    def __init__(self,uid,var,text):
        self.uid = uid
        self.variables = var
        self.text = text
        self.variables["MAILFROM"] = text["From"]
        self.variables["MAILDATE"] = text["Date"]
        self.variables["MAILRECEIVED"] = text["Received"]

def filter(imapmail,mails,filterCriteria,mailbox="inbox"):
    # see http://tools.ietf.org/html/rfc3501#section-6.4.4 (for search)
    # and http://tools.ietf.org/html/rfc3501#section-6.4.5 (for fetch)
    imapmail.select(mailbox)

    data = helper.imapCommand(imapmail,"search",filterCriteria)[0]

    mails = []

    for uid in data.split():
        data = email.message_from_string(helper.imapCommand(imapmail,"fetch",uid,"(rfc822)")[0][1].decode("utf-8"))
        mails.append(mailElement(uid,helper.getConfigValue("variables"),data))
    return mails

def answer(imapmail,mails,subject,text,address="(back)"):
    # see http://tools.ietf.org/html/rfc3501#section-6.4.6 (for store)
    if isinstance(mails,mailElement):
        mails = [mails]

    for mail in mails:
        hashobj = hashlib.md5()
        hashobj.update(("%s: %s"%(subject,text)).encode("utf-8"))
        subjectHash = hashobj.hexdigest()

        if address == "(back)":
            clientMailAddress = mail.variables["MAILFROM"]
        else:
            clientMailAddress = address

        if "NETSEC-Answered-" + subjectHash in helper.imapCommand(imapmail,"fetch",mail.uid,"FLAGS")[0].decode("utf-8"):
            logging.error("Error: Tried to answer to mail (uid %s, addr '%s', Subject '%s') which was already answered."%(mail.uid,clientMailAddress,subject))
        else:
            helper.smtpMail(clientMailAddress,"Content-Type:text/html\nSubject: %s\n\n%s"%(helper.checkForVariable(mail,subject),helper.checkForVariable(mail,text)))
            flag(imapmail,mail,"NETSEC-Answered-" + subjectHash)
    return mails

def move(imapmail,mails,destination):
    # moves the mails from id_list to mailbox destination
    # warning: this alters the UID of the mails!
    if isinstance(mails,mailElement):
        mails = [mails]

    imapmail.create(destination)
    for mail in mails:
        # https://tools.ietf.org/html/rfc6851
        helper.imapCommand(imapmail,"MOVE",mail.uid,destination)
    # no "return mails" here, because the UIDs are invalid after movement.

def flag(imapmail,mails,flag):
    if isinstance(mails,mailElement):
        mails = [mails]

    for mail in mails:
        helper.imapCommand(imapmail,"STORE",mail.uid,"+FLAGS",flag)
    return mails

def log(imapmail,mails,msg,lvl="ERROR"):
    if lvl == "DEBUG":
        logging.debug(msg)
    else:
        logging.error(msg)
    return mails

def delete(imapmail,mails):
    flag(imapmail,mails,"\\DELETED")
    imapmail.expunge()

def save(imapmail,mails):
    if isinstance(mails,mailElement):
        mails = [mails]

    if helper.getConfigValue("settings")["savemode"] == "db":
        sqldatabase = sqlite3.connect(helper.getConfigValue("settings")["database"])
        cursor = sqldatabase.cursor()
        cursor.execute("CREATE TABLE IF NOT EXISTS inbox (addr text,date text,subject text,korrektor text,attachment blob)")

        for mail in mails:
            insertValues = [mail["From"],mail["Date"],mail["Subject"],"(-)"]
            attachments = []

            for payloadPart in mail.walk():
                if payloadPart.get("Content-Transfer-Encoding"):
                    if "base64" in payloadPart.get("Content-Transfer-Encoding"):
                        attachments.append(payloadPart.get_payload())
                    else:
                        attachments.append(base64.b64encode(payloadPart.get_payload()))
            insertValues.append("$".join(attachments))

            cursor.execute("INSERT INTO inbox VALUES (?,?,?,?,?)",insertValues)
            sqldatabase.commit()
            sqldatabase.close()
    elif helper.getConfigValue("settings")["savemode"] == "file":
        retdir = os.getcwd()

        for mail in mails:
            if not os.path.exists("attachments"):
                os.mkdir("attachments")
            os.chdir("attachments")

            if not os.path.exists(mail.variables["MAILFROM"]):
                os.mkdir(mail.variables["MAILFROM"])
            os.chdir(mail.variables["MAILFROM"])

            if not os.path.exists(mail.variables["MAILDATE"]):
                os.mkdir(mail.variables["MAILDATE"])
            os.chdir(mail.variables["MAILDATE"])

            for payloadPart in mail.text.walk():
                if payloadPart.get_filename():
                    attachFile = open(payloadPart.get_filename(),"w")
                elif payloadPart.get_payload():
                    attachFile = open("mailtext.txt","a")
                else:
                    pass

                dataToWrite = str(payloadPart.get_payload(decode="True"))

                if dataToWrite:
                    attachFile.write(dataToWrite)
                attachFile.close()
            os.chdir(retdir)
    return mails
<commit_msg>MOVE returns UIDs now.<commit_after>import logging
import email
import sqlite3
import base64
import hashlib
import os

import helper

class mailElement(object):
    def __init__(self,uid,var,text):
        self.uid = uid
        self.variables = var
        self.text = text
        self.variables["MAILFROM"] = text["From"]
        self.variables["MAILDATE"] = text["Date"]
        self.variables["MAILRECEIVED"] = text["Received"]

def filter(imapmail,mails,filterCriteria,mailbox="inbox"):
    # see http://tools.ietf.org/html/rfc3501#section-6.4.4 (for search)
    # and http://tools.ietf.org/html/rfc3501#section-6.4.5 (for fetch)
    imapmail.select(mailbox)

    data = helper.imapCommand(imapmail,"search",filterCriteria)[0]

    mails = []

    for uid in data.split():
        data = email.message_from_string(helper.imapCommand(imapmail,"fetch",uid,"(rfc822)")[0][1].decode("utf-8"))
        mails.append(mailElement(uid,helper.getConfigValue("variables"),data))
    return mails

def answer(imapmail,mails,subject,text,address="(back)"):
    # see http://tools.ietf.org/html/rfc3501#section-6.4.6 (for store)
    if isinstance(mails,mailElement):
        mails = [mails]

    for mail in mails:
        hashobj = hashlib.md5()
        hashobj.update(("%s: %s"%(subject,text)).encode("utf-8"))
        subjectHash = hashobj.hexdigest()

        if address == "(back)":
            clientMailAddress = mail.variables["MAILFROM"]
        else:
            clientMailAddress = address

        if "NETSEC-Answered-" + subjectHash in helper.imapCommand(imapmail,"fetch",mail.uid,"FLAGS")[0].decode("utf-8"):
            logging.error("Error: Tried to answer to mail (uid %s, addr '%s', Subject '%s') which was already answered."%(mail.uid,clientMailAddress,subject))
        else:
            helper.smtpMail(clientMailAddress,"Content-Type:text/html\nSubject: %s\n\n%s"%(helper.checkForVariable(mail,subject),helper.checkForVariable(mail,text)))
            flag(imapmail,mail,"NETSEC-Answered-" + subjectHash)
    return mails

def move(imapmail,mails,destination):
    # moves the mails from id_list to mailbox destination
    # warning: this alters the UID of the mails!
    if isinstance(mails,mailElement):
        mails = [mails]

    imapmail.create(destination)
    for mail in mails:
        # https://tools.ietf.org/html/rfc6851
        helper.imapCommand(imapmail,"MOVE",mail.uid,destination)
    return mails

def flag(imapmail,mails,flag):
    if isinstance(mails,mailElement):
        mails = [mails]

    for mail in mails:
        helper.imapCommand(imapmail,"STORE",mail.uid,"+FLAGS",flag)
    return mails

def log(imapmail,mails,msg,lvl="ERROR"):
    if lvl == "DEBUG":
        logging.debug(msg)
    else:
        logging.error(msg)
    return mails

def delete(imapmail,mails):
    flag(imapmail,mails,"\\DELETED")
    imapmail.expunge()

def save(imapmail,mails):
    if isinstance(mails,mailElement):
        mails = [mails]

    if helper.getConfigValue("settings")["savemode"] == "db":
        sqldatabase = sqlite3.connect(helper.getConfigValue("settings")["database"])
        cursor = sqldatabase.cursor()
        cursor.execute("CREATE TABLE IF NOT EXISTS inbox (addr text,date text,subject text,korrektor text,attachment blob)")

        for mail in mails:
            insertValues = [mail["From"],mail["Date"],mail["Subject"],"(-)"]
            attachments = []

            for payloadPart in mail.walk():
                if payloadPart.get("Content-Transfer-Encoding"):
                    if "base64" in payloadPart.get("Content-Transfer-Encoding"):
                        attachments.append(payloadPart.get_payload())
                    else:
                        attachments.append(base64.b64encode(payloadPart.get_payload()))
            insertValues.append("$".join(attachments))

            cursor.execute("INSERT INTO inbox VALUES (?,?,?,?,?)",insertValues)
            sqldatabase.commit()
            sqldatabase.close()
    elif helper.getConfigValue("settings")["savemode"] == "file":
        retdir = os.getcwd()

        for mail in mails:
            if not os.path.exists("attachments"):
                os.mkdir("attachments")
            os.chdir("attachments")

            if not os.path.exists(mail.variables["MAILFROM"]):
                os.mkdir(mail.variables["MAILFROM"])
            os.chdir(mail.variables["MAILFROM"])

            if not os.path.exists(mail.variables["MAILDATE"]):
                os.mkdir(mail.variables["MAILDATE"])
            os.chdir(mail.variables["MAILDATE"])

            for payloadPart in mail.text.walk():
                if payloadPart.get_filename():
                    attachFile = open(payloadPart.get_filename(),"w")
                elif payloadPart.get_payload():
                    attachFile = open("mailtext.txt","a")
                else:
                    pass

                dataToWrite = str(payloadPart.get_payload(decode="True"))

                if dataToWrite:
                    attachFile.write(dataToWrite)
                attachFile.close()
            os.chdir(retdir)
    return mails
<|endoftext|>


<commit_before>#
# CORE
#
# based on:
#
# Copyright (c)2010-2012 the Boeing Company.
# See the LICENSE-BOEING file included in this distribution.
#
# author: Tom Goff <thomas.goff@boeing.com>
#
# Copyright (C) 2014 Robert Wuttke <robert@benocs.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

'''
ipaddr.py: helper objects for dealing with IPv4/v6 addresses.
'''

import socket
import struct
import random

import ipaddress

AF_INET = socket.AF_INET
AF_INET6 = socket.AF_INET6

class MacAddr(object):
    def __init__(self, addr):
        self.addr = addr

    def __str__(self):
        return ":".join([("%02x" % x) for x in self.addr])

    def tolinklocal(self):
        ''' Convert the MAC address to a IPv6 link-local address, using EUI 48
        to EUI 64 conversion process per RFC 5342.
        '''
        if not self.addr:
            return IPAddr.fromstring("::")
        tmp = struct.unpack("!Q", '\x00\x00' + self.addr)[0]
        nic = int(tmp) & 0x000000FFFFFF
        oui = int(tmp) & 0xFFFFFF000000
        # toggle U/L bit
        oui ^= 0x020000000000
        # append EUI-48 octets
        oui = (oui << 16) | 0xFFFE000000
        return IPAddr(AF_INET6,  struct.pack("!QQ", 0xfe80 << 48, oui | nic))

    @classmethod
    def fromstring(cls, s):
        addr = "".join([chr(int(x, 16)) for x in s.split(":")])
        return cls(addr)

    @classmethod
    def random(cls):
        tmp = random.randint(0, 0xFFFFFF)
        tmp |= 0x00163E << 24    # use the Xen OID 00:16:3E
        tmpbytes = struct.pack("!Q", tmp)
        return cls(tmpbytes[2:])

class IPAddr(object):
    def __init__(self, af, addr):
        # check if (af, addr) is valid
        tmp = None
        try:
            if af == AF_INET:
                tmp = ipaddress.IPv4Address(addr)
            elif af == AF_INET6:
                tmp = ipaddress.IPv6Address(addr)
            else:
                raise ValueError("invalid af/addr")
        except:
            raise ValueError("invalid af/addr")

        self.af = af
        self.addr = addr
        self.addr_newstyle = tmp

    def isIPv4(self):
        return self.af == AF_INET

    def isIPv6(self):
        return self.af == AF_INET6

    def __str__(self):
        return self.addr_newstyle.compressed

    def __eq__(self, other):
        try:
            return self.addr_newstyle == other.addr_newstyle
        except:
            return False

    def __add__(self, other):
        if self.addr_newstyle.version == 4:
            return ipaddress.IPv4Address(self.addr_newstyle + other.addr_newstyle)
        elif self.addr_newstyle.version == 6:
            return ipaddress.IPv6Address(self.addr_newstyle + other.addr_newstyle)

    def __sub__(self, other):
        try:
            tmp = -int(other)
        except:
            return NotImplemented
        return self.__add__(tmp)

    @classmethod
    def fromstring(cls, s):
        for af in AF_INET, AF_INET6:
            try:
                return cls(af, socket.inet_pton(af, s))
            except Exception as e:
                pass
        raise e

    @staticmethod
    def toint(s):
        ''' convert IPv4 string to 32-bit integer
        '''
        return int(self.addr_newstyle)

class IPPrefix(object):
    def __init__(self, af, prefixstr):
        "prefixstr format: address/prefixlen"
        print('generating prefix for str: %s' % prefixstr)

        self.af = af
        if self.af == AF_INET:
            self.addrlen = 32
            self.prefix = ipaddress.IPv4Network(prefixstr, strict = False)
        elif self.af == AF_INET6:
            self.prefix = ipaddress.IPv6Network(prefixstr, strict = False)
            self.addrlen = 128
        else:
            raise ValueError("invalid address family: '%s'" % self.af)

        tmp = prefixstr.split("/")
        if len(tmp) > 2:
            raise ValueError("invalid prefix: '%s'" % prefixstr)
        if len(tmp) == 2:
            self.prefixlen = int(tmp[1])
        else:
            self.prefixlen = self.addrlen

    def __str__(self):
        print("IPADDR: family: %s, prefix: %s, len: %s" % (str(self.af),
                str(self.prefix), str(self.prefixlen)))
        return str(self.prefix)

    def __eq__(self, other):
        try:
            return other.af == self.af and \
                other.prefixlen == self.prefixlen and \
                other.prefix == self.prefix
        except:
            return False

    def addr(self, hostid):
        tmp = int(hostid)
        if (tmp == 1 or tmp == 0 or tmp == -1) and self.addrlen == self.prefixlen:
            return IPAddr(self.af, self.prefix)
        if tmp == 0 or \
            tmp > (1 << (self.addrlen - self.prefixlen)) - 1 or \
            (self.af == AF_INET and tmp == (1 << (self.addrlen - self.prefixlen)) - 1):
            raise ValueError("invalid hostid for prefix %s: %s" % (str(self), str(hostid)))

        addr = IPAddr(self.af, int(self.prefix.network_address) + int(hostid))
        print('new address: %s' % str(addr))
        return addr

    def minaddr(self):
        return self.prefix.network_address + 1

    def maxaddr(self):
        return self.prefix.broadcast_address - 1

    def numaddr(self):
        return self.prefix.num_addresses - 2

    def prefixstr(self):
        return '%s' % self.prefix

    def netmaskstr(self):
        return '%s' % self.prefix.netmask

class IPv4Prefix(IPPrefix):
    def __init__(self, prefixstr):
        IPPrefix.__init__(self, AF_INET, prefixstr)

class IPv6Prefix(IPPrefix):
    def __init__(self, prefixstr):
        IPPrefix.__init__(self, AF_INET6, prefixstr)

def isIPAddress(af, addrstr):
    try:
        tmp = socket.inet_pton(af, addrstr)
        return True
    except:
        return False

def isIPv4Address(addrstr):
    return isIPAddress(AF_INET, addrstr)

def isIPv6Address(addrstr):
    return isIPAddress(AF_INET6, addrstr)

class NetIDNodeMap():
    # key: netid (as int) - value: current node count of that netid.
    # first node is assigned id 1
    mapping = {}

    @staticmethod
    def register_node(nodeid, netid):
        if not netid in NetIDNodeMap.mapping:
            NetIDNodeMap.mapping[netid] = {}
        if not nodeid in NetIDNodeMap.mapping[netid]:
            if len(NetIDNodeMap.mapping[netid].values()) == 0:
                NetIDNodeMap.mapping[netid][nodeid] = 1
            else:
                NetIDNodeMap.mapping[netid][nodeid] = max(NetIDNodeMap.mapping[netid].values()) + 1

        return NetIDNodeMap.mapping[netid][nodeid]

<commit_msg>[misc/ipaddr] fixed addition, substraction of IPAddr, added wrapper classes IPv4Addr, IPv6Addr<commit_after>#
# CORE
#
# based on:
#
# Copyright (c)2010-2012 the Boeing Company.
# See the LICENSE-BOEING file included in this distribution.
#
# author: Tom Goff <thomas.goff@boeing.com>
#
# Copyright (C) 2014 Robert Wuttke <robert@benocs.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

'''
ipaddr.py: helper objects for dealing with IPv4/v6 addresses.
'''

import socket
import struct
import random

import ipaddress

AF_INET = socket.AF_INET
AF_INET6 = socket.AF_INET6

class MacAddr(object):
    def __init__(self, addr):
        self.addr = addr

    def __str__(self):
        return ":".join([("%02x" % x) for x in self.addr])

    def tolinklocal(self):
        ''' Convert the MAC address to a IPv6 link-local address, using EUI 48
        to EUI 64 conversion process per RFC 5342.
        '''
        if not self.addr:
            return IPAddr.fromstring("::")
        tmp = struct.unpack("!Q", '\x00\x00' + self.addr)[0]
        nic = int(tmp) & 0x000000FFFFFF
        oui = int(tmp) & 0xFFFFFF000000
        # toggle U/L bit
        oui ^= 0x020000000000
        # append EUI-48 octets
        oui = (oui << 16) | 0xFFFE000000
        return IPAddr(AF_INET6,  struct.pack("!QQ", 0xfe80 << 48, oui | nic))

    @classmethod
    def fromstring(cls, s):
        addr = "".join([chr(int(x, 16)) for x in s.split(":")])
        return cls(addr)

    @classmethod
    def random(cls):
        tmp = random.randint(0, 0xFFFFFF)
        tmp |= 0x00163E << 24    # use the Xen OID 00:16:3E
        tmpbytes = struct.pack("!Q", tmp)
        return cls(tmpbytes[2:])

class IPAddr(object):
    def __init__(self, af, addr):
        # check if (af, addr) is valid
        tmp = None
        try:
            if af == AF_INET:
                tmp = ipaddress.IPv4Address(addr)
            elif af == AF_INET6:
                tmp = ipaddress.IPv6Address(addr)
            else:
                raise ValueError("invalid af/addr")
        except:
            raise ValueError("invalid af/addr")

        self.af = af
        self.addr = addr
        self.addr_newstyle = tmp

    def isIPv4(self):
        return self.af == AF_INET

    def isIPv6(self):
        return self.af == AF_INET6

    def __str__(self):
        return self.addr_newstyle.compressed

    def __eq__(self, other):
        try:
            return self.addr_newstyle == other.addr_newstyle
        except:
            return False

    def __add__(self, other):
        if not self.__class__ == other.__class:
            raise ValueError
        if isinstance(other, IPAddr):
            if self.addr_newstyle.version == 4:
                return IPAddr(AF_INET,
                        str(ipaddress.IPv4Address(self.addr_newstyle + other.addr_newstyle)))
            elif self.addr_newstyle.version == 6:
                return IPAddr(AF_INET6,
                        str(ipaddress.IPv64Address(self.addr_newstyle + other.addr_newstyle)))
        elif isinstance(other, ipaddress.IPv4Address):
            return IPAddr(AF_INET, str(ipaddress.IPv4Address(self.addr_newstyle + other)))
        elif isinstance(other, ipaddress.IPv6Address):
            return IPAddr(AF_INET6, str(ipaddress.IPv64Address(self.addr_newstyle + other)))
        else:
            raise ValueError

    def __sub__(self, other):
        try:
            tmp = -int(other)
        except:
            return NotImplemented
        return self.__add__(tmp)

    @classmethod
    def fromstring(cls, s):
        for af in AF_INET, AF_INET6:
            try:
                return cls(af, socket.inet_pton(af, s))
            except Exception as e:
                pass
        raise e

    @staticmethod
    def toint(s):
        ''' convert IPv4 string to 32-bit integer
        '''
        return int(self.addr_newstyle)

class IPv4Addr(IPAddr):
    def __init__(self, addr):
        super().__init__(AF_INET, addr)

class IPv6Addr(IPAddr):
    def __init__(self, addr):
        super().__init__(AF_INET6, addr)

class IPPrefix(object):
    def __init__(self, af, prefixstr):
        "prefixstr format: address/prefixlen"
        print('generating prefix for str: %s' % prefixstr)

        self.af = af
        if self.af == AF_INET:
            self.addrlen = 32
            self.prefix = ipaddress.IPv4Network(prefixstr, strict = False)
        elif self.af == AF_INET6:
            self.prefix = ipaddress.IPv6Network(prefixstr, strict = False)
            self.addrlen = 128
        else:
            raise ValueError("invalid address family: '%s'" % self.af)

        tmp = prefixstr.split("/")
        if len(tmp) > 2:
            raise ValueError("invalid prefix: '%s'" % prefixstr)
        if len(tmp) == 2:
            self.prefixlen = int(tmp[1])
        else:
            self.prefixlen = self.addrlen

    def __str__(self):
        print("IPADDR: family: %s, prefix: %s, len: %s" % (str(self.af),
                str(self.prefix), str(self.prefixlen)))
        return str(self.prefix)

    def __eq__(self, other):
        try:
            return other.af == self.af and \
                other.prefixlen == self.prefixlen and \
                other.prefix == self.prefix
        except:
            return False

    def addr(self, hostid):
        tmp = int(hostid)
        if (tmp == 1 or tmp == 0 or tmp == -1) and self.addrlen == self.prefixlen:
            return IPAddr(self.af, self.prefix)
        if tmp == 0 or \
            tmp > (1 << (self.addrlen - self.prefixlen)) - 1 or \
            (self.af == AF_INET and tmp == (1 << (self.addrlen - self.prefixlen)) - 1):
            raise ValueError("invalid hostid for prefix %s: %s" % (str(self), str(hostid)))

        addr = IPAddr(self.af, int(self.prefix.network_address) + int(hostid))
        print('new address: %s' % str(addr))
        return addr

    def minaddr(self):
        return self.prefix.network_address + 1

    def maxaddr(self):
        return self.prefix.broadcast_address - 1

    def numaddr(self):
        return self.prefix.num_addresses - 2

    def prefixstr(self):
        return '%s' % self.prefix

    def netmaskstr(self):
        return '%s' % self.prefix.netmask

class IPv4Prefix(IPPrefix):
    def __init__(self, prefixstr):
        IPPrefix.__init__(self, AF_INET, prefixstr)

class IPv6Prefix(IPPrefix):
    def __init__(self, prefixstr):
        IPPrefix.__init__(self, AF_INET6, prefixstr)

def isIPAddress(af, addrstr):
    try:
        tmp = socket.inet_pton(af, addrstr)
        return True
    except:
        return False

def isIPv4Address(addrstr):
    return isIPAddress(AF_INET, addrstr)

def isIPv6Address(addrstr):
    return isIPAddress(AF_INET6, addrstr)

class NetIDNodeMap():
    # key: netid (as int) - value: current node count of that netid.
    # first node is assigned id 1
    mapping = {}

    @staticmethod
    def register_node(nodeid, netid):
        if not netid in NetIDNodeMap.mapping:
            NetIDNodeMap.mapping[netid] = {}
        if not nodeid in NetIDNodeMap.mapping[netid]:
            if len(NetIDNodeMap.mapping[netid].values()) == 0:
                NetIDNodeMap.mapping[netid][nodeid] = 1
            else:
                NetIDNodeMap.mapping[netid][nodeid] = max(NetIDNodeMap.mapping[netid].values()) + 1

        return NetIDNodeMap.mapping[netid][nodeid]

<|endoftext|>


<commit_before>#! /usr/bin/env python

# Victor Calderon
# Vanderbilt University
# Project: Digits dataset for VandyAstroML project

"""
Description: Decision-tree algorithm on the dataset "Digits" from Scikit-learn.
"""
# modules for Python2/3
from __future__ import division, print_function, absolute_import

# Importing modules
import numpy as num
import random
from sklearn import datasets
from collections import Counter

class Best_Choices():
        def __init_(self, results=None, true_tree=None, false_tree=None,col=-1 ):
            self.results    = results # Dictionary of results
            self.true_tree  = None    # Subtree for the `true` tree
            self.false_tree = None    # SubTree for the `false` tree
            self.col        = -1      # Chosen column number

def splitting_branches(data, ncol, val):
    """
    Separatates `ncol` from data into two branches, depending on the conditions
    based on `val`

    Parameters
    ----------
    data: array_like
        N-dimensional array with the data

    ncol: int
        column number used to categorized the two output sets (arrays).

    val: string, int, or float
        value used to categorize `data`

    Returns
    -------
    set_arrs: array_like
        array containing both sets, i.e. arr1 and arr2, based on the criteria of
        `val`.
    """
    # Checking if value is an integer, a float, or something else
    if isinstance(val, int) or
        val_type = lambda data: data[ncol] >= val # for numbers
    else:
        val_type = lambda data: data[ncol] == val # for strings or other
    # Saving into arrays (and making sure they are lists, and not arrays)
    set_corr = [row for row in data if val_type(row)]
    set_fail = [row for row in data if not val_type(row)]
    set_arrs = (set_corr, set_fail)

    return set_arrs

def counter_of_targets(data):
    """
    Calculates the total number of occurences for each of the possible values of
    the targets for each (sub)array.

    Parameters
    ----------
    data: array_like
        N-dimensional array or 1-d array

    Returns
    -------
    Count_dict: dictionary
        Dictionary with possible values and their counts
    """
    ## Assuming it's a list
    Count_obj = Counter(num.array(data).T[-1])
    Count_dict = {}
    for key in Count_obj.keys():
    Count_dict[key] = Count_obj[key]

    return Count_dict

def entropy_calculation(data):
    """
    Calculated the `entropy` of the dataset. This is a measure of how unpure
    the mix of `target` values is. Ideally, entropy==0.

    Parameters
    ----------
    data_dict: dictionary
        dictionary containing counts for possible `target` values

    Returns
    -------
    ent_val: float
        value for the estimated entropy of the given `data`
    """
    counts  = counter_of_targets(data)
    ent_val = 0.
    # Looping over all `target` values in `counts`
    for key in counts.keys():
        p_val = counts[key]/float(len(data))
        # Entropy formula
        ent_val -= p_val*num.log2(p_val)

    return ent_val

def Tree_training(data, estimator=entropy_calculation):
    """
    This function iterates over all possible values for each of the columns
    of `data` and constructs the whole Decision Tree structure

    Parameters
    ----------
    data: array_like
        N-dimensional array, with `targets` being the last column.

    estimator: function
        Estimator that determines the cost function of the data, i.e. how
        (un)pure `data` is

    Returns
    -------
    Best_vals: class
        This class contains information on the best values obtained through the
        Decision Tree constructed.
    """

def main():
    ## Loading dataset
    digits = datasets.load_digits()
    # Digits - Data
    digits_dat = digits['data']
    n_samples  = digits_dat.shape[0]
    n_features = digits_dat.shape[1]
    # Digits - target names
    digits_tnames = digits['target_names'].astype(int)
    # Digits - target values
    digits_target = digits['target']

    ## Training and control samples
    # Selects 80 percent of sample as training sample
    # and the other 20 percent as the control sample.
    # Want to select 80 percent of all types of targets
    train_frac = 0.8
    # training set - indices
    train_idx  = []
    for target in digits_tnames:
        tnames_idx    = num.where(digits_target==target)[0]
        tnames_size   = int(tnames_idx.size*train_frac)
        tnames_sample = random.sample(tnames_idx, tnames_size)
        train_idx.extend(tnames_sample)
    train_idx = num.array(train_idx)
    # Control set - indices
    cont_idx  = set(range(len(digits_target))).difference(train_idx)
    cont_idx  = num.array(list(cont_idx))
    # Training set - dictionary
    train_dict = {}
    train_dict['data'  ] = digits_dat   [train_idx]
    train_dict['target'] = digits_target[train_idx]
    train_data_target    = num.column_stack((train_dict['data'],
        train_dict['target']))
    # Combining data and target
    # Control set - dictionary
    cont_dict = {}
    cont_dict['data'  ] = digits_dat   [cont_idx]
    cont_dict['target'] = digits_target[cont_idx]
    cont_data_target    = num.column_stack((cont_dict['data'],
        cont_dict['target']))

<commit_msg>Indentation<commit_after>#! /usr/bin/env python

# Victor Calderon
# Vanderbilt University
# Project: Digits dataset for VandyAstroML project

"""
Description: Decision-tree algorithm on the dataset "Digits" from Scikit-learn.
"""
# modules for Python2/3
from __future__ import division, print_function, absolute_import

# Importing modules
import numpy as num
import random
from sklearn import datasets
from collections import Counter

class Best_Choices():
    def __init_(self, results=None, true_tree=None, false_tree=None,col=-1 ):
        self.results    = results # Dictionary of results
        self.true_tree  = None    # Subtree for the `true` tree
        self.false_tree = None    # SubTree for the `false` tree
        self.col        = -1      # Chosen column number

def splitting_branches(data, ncol, val):
    """
    Separatates `ncol` from data into two branches, depending on the conditions
    based on `val`

    Parameters
    ----------
    data: array_like
        N-dimensional array with the data

    ncol: int
        column number used to categorized the two output sets (arrays).

    val: string, int, or float
        value used to categorize `data`

    Returns
    -------
    set_arrs: array_like
        array containing both sets, i.e. arr1 and arr2, based on the criteria of
        `val`.
    """
    # Checking if value is an integer, a float, or something else
    if isinstance(val, int) or
        val_type = lambda data: data[ncol] >= val # for numbers
    else:
        val_type = lambda data: data[ncol] == val # for strings or other
    # Saving into arrays (and making sure they are lists, and not arrays)
    set_corr = [row for row in data if val_type(row)]
    set_fail = [row for row in data if not val_type(row)]
    set_arrs = (set_corr, set_fail)

    return set_arrs

def counter_of_targets(data):
    """
    Calculates the total number of occurences for each of the possible values of
    the targets for each (sub)array.

    Parameters
    ----------
    data: array_like
        N-dimensional array or 1-d array

    Returns
    -------
    Count_dict: dictionary
        Dictionary with possible values and their counts
    """
    ## Assuming it's a list
    Count_obj = Counter(num.array(data).T[-1])
    Count_dict = {}
    for key in Count_obj.keys():
    Count_dict[key] = Count_obj[key]

    return Count_dict

def entropy_calculation(data):
    """
    Calculated the `entropy` of the dataset. This is a measure of how unpure
    the mix of `target` values is. Ideally, entropy==0.

    Parameters
    ----------
    data_dict: dictionary
        dictionary containing counts for possible `target` values

    Returns
    -------
    ent_val: float
        value for the estimated entropy of the given `data`
    """
    counts  = counter_of_targets(data)
    ent_val = 0.
    # Looping over all `target` values in `counts`
    for key in counts.keys():
        p_val = counts[key]/float(len(data))
        # Entropy formula
        ent_val -= p_val*num.log2(p_val)

    return ent_val

def Tree_training(data, estimator=entropy_calculation):
    """
    This function iterates over all possible values for each of the columns
    of `data` and constructs the whole Decision Tree structure

    Parameters
    ----------
    data: array_like
        N-dimensional array, with `targets` being the last column.

    estimator: function
        Estimator that determines the cost function of the data, i.e. how
        (un)pure `data` is

    Returns
    -------
    Best_vals: class
        This class contains information on the best values obtained through the
        Decision Tree constructed.
    """

def main():
    ## Loading dataset
    digits = datasets.load_digits()
    # Digits - Data
    digits_dat = digits['data']
    n_samples  = digits_dat.shape[0]
    n_features = digits_dat.shape[1]
    # Digits - target names
    digits_tnames = digits['target_names'].astype(int)
    # Digits - target values
    digits_target = digits['target']

    ## Training and control samples
    # Selects 80 percent of sample as training sample
    # and the other 20 percent as the control sample.
    # Want to select 80 percent of all types of targets
    train_frac = 0.8
    # training set - indices
    train_idx  = []
    for target in digits_tnames:
        tnames_idx    = num.where(digits_target==target)[0]
        tnames_size   = int(tnames_idx.size*train_frac)
        tnames_sample = random.sample(tnames_idx, tnames_size)
        train_idx.extend(tnames_sample)
    train_idx = num.array(train_idx)
    # Control set - indices
    cont_idx  = set(range(len(digits_target))).difference(train_idx)
    cont_idx  = num.array(list(cont_idx))
    # Training set - dictionary
    train_dict = {}
    train_dict['data'  ] = digits_dat   [train_idx]
    train_dict['target'] = digits_target[train_idx]
    train_data_target    = num.column_stack((train_dict['data'],
        train_dict['target']))
    # Combining data and target
    # Control set - dictionary
    cont_dict = {}
    cont_dict['data'  ] = digits_dat   [cont_idx]
    cont_dict['target'] = digits_target[cont_idx]
    cont_data_target    = num.column_stack((cont_dict['data'],
        cont_dict['target']))

<|endoftext|>


<commit_before># License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models, api
import odoo.addons.decimal_precision as dp

class SaleOrder(models.Model):

    _inherit = 'sale.order'

    # state = fields.Selection(selection_add=[('reserve', 'Reserved')])
    state = fields.Selection([
        ('draft', 'Quotation'),
        ('sent', 'Quotation Sent'),
        ('reserve', 'Reserved'),
        ('sale', 'Sales Order'),
        ('done', 'Done'),
        ('cancel', 'Cancelled'),
    ])

    @api.multi
    @api.depends('state',
                 'order_line.reservation_ids',
                 'order_line.is_stock_reservable')
    def _compute_stock_reservation(self):
        for sale in self:
            has_stock_reservation = False
            is_stock_reservable = False
            for line in sale.order_line:
                if line.reservation_ids:
                    has_stock_reservation = True
                if line.is_stock_reservable:
                    is_stock_reservable = True
            if sale.state not in ('draft', 'sent', 'reserve'):
                is_stock_reservable = False
            sale.is_stock_reservable = is_stock_reservable
            sale.has_stock_reservation = has_stock_reservation

    @api.model
    def create(self, vals):
        res = super().create(vals)
        if res.state == 'reserve':
            res.order_reserve()
        return res

    def order_reserve(self):
        self.write({'state': 'reserve'})
        lines = self.mapped('order_line').filtered(
            lambda r: r.product_id and r.product_id.type != 'service')
        lines.stock_reserve()
        return True

    def open_stock_reservation(self):
        self.ensure_one()
        action = self.env.ref('stock_reserve.action_stock_reservation_tree').read()[0]
        action['domain'] = [('sale_id', 'in', self.ids)]
        action['context'] = {'search_default_draft': 1,
                             'search_default_reserved': 1,
                             'search_default_waiting': 1,
                             'search_default_partially_available': 1,
                            }
        return action

class SaleOrderLine(models.Model):

    _inherit = 'sale.order.line'

    unique_js_id = fields.Char('', size=64, copy=False)
    temp_unique_js_id = fields.Char('', size=64, copy=False)
    qty_reserved = fields.Float(readonly=True,
                                related='product_id.reservation_count',
                                digits=dp.get_precision('Product Unit \
                                                  of Measure'))

    @api.multi
    @api.depends('state', 'product_id', 'reservation_ids')
    def _compute_is_stock_reservation(self):
        for line in self:
            reservable = False
            if (not (line.state not in ('draft', 'reserve') or
                     line._get_procure_method() == 'make_to_order' or
                     not line.product_id or
                     line.product_id.type == 'service') and
                    not line.reservation_ids):
                reservable = True
            line.is_stock_reservable = reservable

    def _test_block_on_reserve(self, vals):
        super()._test_block_on_reserve(vals)
        return False

    @api.multi
    def write(self, vals):
        ctx = dict(self.env.context)
        for line in self:
            unique_js_id = vals.get('unique_js_id', line.unique_js_id)
            temp_unique_js_id = vals.get('temp_unique_js_id',
                                         line.temp_unique_js_id)

            if temp_unique_js_id:
                if vals.get('reservation_ids', False):
                    vals.pop('reservation_ids')
                if unique_js_id:
                    reserve_to_delete = self.env['stock.reservation'].search(
                        [('unique_js_id', '=', unique_js_id)])
                    if reserve_to_delete:
                        reserve_to_delete.unlink()
                elif line.reservation_ids:
                    line.reservation_ids.unlink()
                new_reserv = self.env['stock.reservation'].search(
                    [('unique_js_id', '=', temp_unique_js_id)])
                if new_reserv:
                    new_reserv.sale_line_id = line.id
                    new_reserv.origin = line.order_id.name
                else:
                    ctx['later'] = True
                vals['unique_js_id'] = temp_unique_js_id
                vals['temp_unique_js_id'] = ''
        return super(SaleOrderLine, self.with_context(ctx)).write(vals)

    @api.model
    def create(self, vals):
        context2 = dict(self._context)
        context2.pop('default_state', False)
        if vals.get('temp_unique_js_id', False):
            vals['unique_js_id'] = vals['temp_unique_js_id']
            vals.pop('temp_unique_js_id', None)
            res = super(SaleOrderLine, self.with_context(context2)).create(
                vals)
            reserve = self.env['stock.reservation'].search(
                [('unique_js_id', '=', res.unique_js_id)])
            if reserve:
                reserve.sale_line_id = res.id
                reserve.origin = res.order_id.name
        else:
            res = super(SaleOrderLine, self.with_context(context2)).create(
                vals)
        return res

    @api.multi
    def read(self, fields=None, load='_classic_read'):
        if 'unique_js_id' in fields:
            reserv_obj = self.env['stock.reservation']
            for line in self:
                self._cr.execute("select sale_order.state, unique_js_id from "
                                 "sale_order_line inner join sale_order on "
                                 "sale_order.id = sale_order_line.order_id "
                                 "where sale_order_line.id = %s"
                                 % str(line.id))
                line_data = self._cr.fetchone()
                if line_data and line_data[0] == "reserve" and line_data[1]:
                    reserves = reserv_obj.search([('unique_js_id', '=',
                                                   line_data[1]),
                                                  ('state', '!=',
                                                   'cancel')])
                    while len(reserves) > 1:
                        reserv = reserves.pop()
                        reserv_obj.unlink(reserv)
                    if reserves and not reserves[0].sale_line_id:
                        reserves[0].sale_line_id = line.id
                        reserves[0].origin = line.order_id.name

        return super().read(fields=fields, load=load)

    @api.multi
    def unlink(self):
        for line in self:
            if line.unique_js_id:
                reserve = self.env['stock.reservation'].search(
                    [('unique_js_id', '=', line.unique_js_id)])
                reserve.unlink()
            if line.temp_unique_js_id:
                reserve = self.env['stock.reservation'].search(
                    [('unique_js_id', '=', line.temp_unique_js_id)])
                reserve.unlink()
        return super().unlink()

    def stock_reserve(self):
        if self.env.context.get('later', False):
            return True

        for line in self:
            if line.order_id.state in ('draft', 'sent', 'progress', 'done',
                                       'manual'):
                continue
            if not line.is_stock_reservable:
                continue
            if line.reservation_ids:
                for reserve in line.reservation_ids:
                    reserve.reassign()
            else:
                vals = line._prepare_stock_reservation()
                reservation = self.env['stock.reservation'].create(vals)
                reservation.reserve()
        return True
<commit_msg>[FIX]reserve_without_save_sale: recogido pedido y comercial en los movimientos de reservas<commit_after># License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models, api
import odoo.addons.decimal_precision as dp

class SaleOrder(models.Model):

    _inherit = 'sale.order'

    # state = fields.Selection(selection_add=[('reserve', 'Reserved')])
    state = fields.Selection([
        ('draft', 'Quotation'),
        ('sent', 'Quotation Sent'),
        ('reserve', 'Reserved'),
        ('sale', 'Sales Order'),
        ('done', 'Done'),
        ('cancel', 'Cancelled'),
    ])

    @api.multi
    @api.depends('state',
                 'order_line.reservation_ids',
                 'order_line.is_stock_reservable')
    def _compute_stock_reservation(self):
        for sale in self:
            has_stock_reservation = False
            is_stock_reservable = False
            for line in sale.order_line:
                if line.reservation_ids:
                    has_stock_reservation = True
                if line.is_stock_reservable:
                    is_stock_reservable = True
            if sale.state not in ('draft', 'sent', 'reserve'):
                is_stock_reservable = False
            sale.is_stock_reservable = is_stock_reservable
            sale.has_stock_reservation = has_stock_reservation

    @api.model
    def create(self, vals):
        res = super().create(vals)
        if res.state == 'reserve':
            res.order_reserve()
        return res

    def order_reserve(self):
        self.write({'state': 'reserve'})
        lines = self.mapped('order_line').filtered(
            lambda r: r.product_id and r.product_id.type != 'service')
        lines.stock_reserve()
        return True

    def open_stock_reservation(self):
        self.ensure_one()
        action = self.env.ref('stock_reserve.action_stock_reservation_tree').read()[0]
        action['domain'] = [('sale_id', 'in', self.ids)]
        action['context'] = {'search_default_draft': 1,
                             'search_default_reserved': 1,
                             'search_default_waiting': 1,
                             'search_default_partially_available': 1,
                            }
        return action

class SaleOrderLine(models.Model):

    _inherit = 'sale.order.line'

    unique_js_id = fields.Char('', size=64, copy=False)
    temp_unique_js_id = fields.Char('', size=64, copy=False)
    qty_reserved = fields.Float(readonly=True,
                                related='product_id.reservation_count',
                                digits=dp.get_precision('Product Unit \
                                                  of Measure'))

    @api.multi
    @api.depends('state', 'product_id', 'reservation_ids')
    def _compute_is_stock_reservation(self):
        for line in self:
            reservable = False
            if (not (line.state not in ('draft', 'reserve') or
                     line._get_procure_method() == 'make_to_order' or
                     not line.product_id or
                     line.product_id.type == 'service') and
                    not line.reservation_ids):
                reservable = True
            line.is_stock_reservable = reservable

    def _test_block_on_reserve(self, vals):
        super()._test_block_on_reserve(vals)
        return False

    @api.multi
    def write(self, vals):
        ctx = dict(self.env.context)
        for line in self:
            unique_js_id = vals.get('unique_js_id', line.unique_js_id)
            temp_unique_js_id = vals.get('temp_unique_js_id',
                                         line.temp_unique_js_id)

            if temp_unique_js_id:
                if vals.get('reservation_ids', False):
                    vals.pop('reservation_ids')
                if unique_js_id:
                    reserve_to_delete = self.env['stock.reservation'].search(
                        [('unique_js_id', '=', unique_js_id)])
                    if reserve_to_delete:
                        reserve_to_delete.unlink()
                elif line.reservation_ids:
                    line.reservation_ids.unlink()
                new_reserv = self.env['stock.reservation'].search(
                    [('unique_js_id', '=', temp_unique_js_id)])
                if new_reserv:
                    new_reserv.sale_line_id = line.id
                    new_reserv.origin = line.order_id.name
                else:
                    ctx['later'] = True
                vals['unique_js_id'] = temp_unique_js_id
                vals['temp_unique_js_id'] = ''
        return super(SaleOrderLine, self.with_context(ctx)).write(vals)

    @api.model
    def create(self, vals):
        context2 = dict(self._context)
        context2.pop('default_state', False)
        if vals.get('temp_unique_js_id', False):
            vals['unique_js_id'] = vals['temp_unique_js_id']
            vals.pop('temp_unique_js_id', None)
            res = super(SaleOrderLine, self.with_context(context2)).create(
                vals)
            reserve = self.env['stock.reservation'].search(
                [('unique_js_id', '=', res.unique_js_id)])
            if reserve:
                reserve.sale_line_id = res.id
                reserve.origin = res.order_id.name
        else:
            res = super(SaleOrderLine, self.with_context(context2)).create(
                vals)
        return res

    @api.multi
    def read(self, fields=None, load='_classic_read'):
        if 'unique_js_id' in fields:
            reserv_obj = self.env['stock.reservation']
            for line in self:
                self._cr.execute("select sale_order.state, unique_js_id from "
                                 "sale_order_line inner join sale_order on "
                                 "sale_order.id = sale_order_line.order_id "
                                 "where sale_order_line.id = %s"
                                 % str(line.id))
                line_data = self._cr.fetchone()
                if line_data and line_data[0] == "reserve" and line_data[1]:
                    reserves = reserv_obj.search([('unique_js_id', '=',
                                                   line_data[1]),
                                                  ('state', '!=',
                                                   'cancel')])
                    while len(reserves) > 1:
                        reserv = reserves.pop()
                        reserv_obj.unlink(reserv)
                    if reserves and not reserves[0].sale_line_id:
                        reserves[0].sale_line_id = line.id
                        reserves[0].origin = line.order_id.name

        return super().read(fields=fields, load=load)

    @api.multi
    def unlink(self):
        for line in self:
            if line.unique_js_id:
                reserve = self.env['stock.reservation'].search(
                    [('unique_js_id', '=', line.unique_js_id)])
                reserve.unlink()
            if line.temp_unique_js_id:
                reserve = self.env['stock.reservation'].search(
                    [('unique_js_id', '=', line.temp_unique_js_id)])
                reserve.unlink()
        return super().unlink()

    @api.multi
    def _prepare_stock_reservation(self, date_validity=False, note=False):
        res = super()._prepare_stock_reservation(date_validity=date_validity, note=note)
        res['sale_id'] = self.order_id.id
        res['user_id'] = self.order_id.user_id.id
        return res

    def stock_reserve(self):
        if self.env.context.get('later', False):
            return True

        for line in self:
            if line.order_id.state in ('draft', 'sent', 'progress', 'done',
                                       'manual'):
                continue
            if not line.is_stock_reservable:
                continue
            if line.reservation_ids:
                for reserve in line.reservation_ids:
                    reserve.reassign()
            else:
                vals = line._prepare_stock_reservation()
                reservation = self.env['stock.reservation'].create(vals)
                reservation.reserve()
                reservation.write({'sale_line_id': line.id})
                reservation.move_id.write({'origin': line.order_id.name})
        return True
<|endoftext|>


<commit_before>from django.db import models
from expedient.common.xmlrpc_serverproxy.models import PasswordXMLRPCServerProxy

class FVServerProxy(PasswordXMLRPCServerProxy):
    name = models.CharField("FV name",max_length = 40)

    def get_switches(self):
        """
        Change from FV format to CH format
        """
        dpids = self.api.listDevices()
        infos = [self.api.getDeviceInfo(d) for d in dpids]
        return zip(dpids, infos)

    def get_links(self):
        """
        Change from FV format to CH format
        """
        return [(l.pop("srcDPID"),
                 l.pop("srcPort"),
                 l.pop("dstDPID"),
                 l.pop("dstPort"),
                 l) for l in self.api.getLinks()]

class CallBackServerProxy(models.Model):
    '''
    Stores some information for simple callbacks.
    '''

    username = models.CharField(max_length=100)
    url = models.URLField("Server URL", max_length=1024, verify_exists=False)
    cookie = models.TextField()

    def __getattr__(self, name):
        if name == "proxy":
            from xmlrpclib import ServerProxy
            self.proxy = ServerProxy(self.url)
            return self.proxy
        else:
            return getattr(self.proxy, name)

    def is_available(self):
        '''Call the server's ping method, and see if we get a pong'''
        try:
            if self.ping("PING") == "PONG: PING":
                return True
        except Exception, e:
            import traceback
            print "Exception while pinging server: %s" % e
            traceback.print_exc()
        return False
    <commit_msg>forgotten file<commit_after>from django.db import models
from expedient.common.xmlrpc_serverproxy.models import PasswordXMLRPCServerProxy

class FVServerProxy(PasswordXMLRPCServerProxy):
    name = models.CharField("FV name",max_length = 40)

    @classmethod
    def get_or_create_fv(self):
        fv = self.objects.all()
        if (len(fv) == 0):
            fv = self.objects.create(name="",
                username="",
                password="",
                url = "",)
        else:
            fv = fv[0]

        return fv

    def get_switches(self):
        """
        Change from FV format to CH format
        """
        dpids = self.api.listDevices()
        infos = [self.api.getDeviceInfo(d) for d in dpids]
        return zip(dpids, infos)

    def get_links(self):
        """
        Change from FV format to CH format
        """
        return [(l.pop("srcDPID"),
                 l.pop("srcPort"),
                 l.pop("dstDPID"),
                 l.pop("dstPort"),
                 l) for l in self.api.getLinks()]

class CallBackServerProxy(models.Model):
    '''
    Stores some information for simple callbacks.
    '''

    username = models.CharField(max_length=100)
    url = models.URLField("Server URL", max_length=1024, verify_exists=False)
    cookie = models.TextField()

    def __getattr__(self, name):
        if name == "proxy":
            from xmlrpclib import ServerProxy
            self.proxy = ServerProxy(self.url)
            return self.proxy
        else:
            return getattr(self.proxy, name)

    def is_available(self):
        '''Call the server's ping method, and see if we get a pong'''
        try:
            if self.ping("PING") == "PONG: PING":
                return True
        except Exception, e:
            import traceback
            print "Exception while pinging server: %s" % e
            traceback.print_exc()
        return False
    <|endoftext|>