<commit_before># Copyright (C) 2010 Linaro Limited
#
# Author: <NAME> <<EMAIL>>
#
# This file is part of Launch Control.
#
# Launch Control is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License version 3
# as published by the Free Software Foundation
#
# Launch Control 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 Affero General Public License
# along with Launch Control.  If not, see <http://www.gnu.org/licenses/>.

"""
XMP-RPC API
"""

import decimal
import logging
import xmlrpclib

from django.contrib.auth.models import User, Group
from django.core.urlresolvers import reverse
from django.db import IntegrityError, DatabaseError
from linaro_django_xmlrpc.models import (
    ExposedAPI,
    Mapper,
    xml_rpc_signature,
)

from dashboard_app import __version__
from dashboard_app.models import (
    Bundle,
    BundleStream,
    DataView,
)


class errors:
    """
    A namespace for error codes that may be returned by various XML-RPC
    methods. Where applicable existing status codes from HTTP protocol
    are reused
    """
    AUTH_FAILED = 100
    AUTH_BLOCKED = 101
    FORBIDDEN = 403
    NOT_FOUND = 404
    CONFLICT = 409
    INTERNAL_SERVER_ERROR = 500
    NOT_IMPLEMENTED = 501


class DashboardAPI(ExposedAPI):
    """
    Dashboard API object.

    All public methods are automatically exposed as XML-RPC methods
    """

    data_view_connection = DataView.get_connection()

    @xml_rpc_signature('str')
    def version(self):
        """
        Name
        ----
        `version` ()

        Description
        -----------
        Return dashboard server version. The version is a string with
        dots separating five components.

        The components are:
            1. major version
            2. minor version
            3. micro version
            4. release level
            5. serial

        See: http://docs.python.org/library/sys.html#sys.version_info

        Return value
        -------------
        Server version string
        """
        return ".".join(map(str, __version__))

    @xml_rpc_signature('str', 'str', 'str', 'str')
    def put(self, content, content_filename, pathname):
        """
        Name
        ----
        `put` (`content`, `content_filename`, `pathname`)

        Description
        -----------
        Upload a bundle to the server.

        Arguments
        ---------
        `content`: string
            Full text of the bundle. This *SHOULD* be a valid JSON
            document and it *SHOULD* match the "Dashboard Bundle Format
            1.0" schema. The SHA1 of the content *MUST* be unique or a
            ``Fault(409, "...")`` is raised. This is used to protect
            from simple duplicate submissions.
        `content_filename`: string
            Name of the file that contained the text of the bundle. The
            `content_filename` can be an arbitrary string and will be
            stored along with the content for reference.
        `pathname`: string
            Pathname of the bundle stream where a new bundle should
            be created and stored. This argument *MUST* designate a
            pre-existing bundle stream or a ``Fault(404, "...")`` exception
            is raised. In addition the user *MUST* have access
            permission to upload bundles there or a ``Fault(403, "...")``
            exception is raised. See below for access rules.

        Return value
        ------------
        If all goes well this function returns the SHA1 of the content.

        Exceptions raised
        -----------------
        404
            Either:

                - Bundle stream not found
                - Uploading to specified stream is not permitted
        409
            Duplicate bundle content

        Rules for bundle stream access
        ------------------------------
        The following rules govern bundle stream upload access rights:
            - all anonymous streams are accessible
            - personal streams are accessible to owners
            - team streams are accessible to team members

        """
        try:
            logging.debug("Getting bundle stream")
            bundle_stream = BundleStream.objects.accessible_by_principal(self.user).get(pathname=pathname)
        except BundleStream.DoesNotExist:
            logging.debug("Bundle stream does not exists, aborting")
            raise xmlrpclib.Fault(errors.NOT_FOUND,
                    "Bundle stream not found")
        try:
            logging.debug("Creating bundle object")
            bundle = Bundle.objects.create_with_content(bundle_stream, self.user, content_filename, content)
        except (IntegrityError, ValueError) as exc:
            logging.debug("Raising xmlrpclib.Fault(errors.CONFLICT)")
            raise xmlrpclib.Fault(errors.CONFLICT, str(exc))
        except:
            logging.exception("big oops")
            raise
        else:   
            logging.debug("Deserializing bundle")
            bundle.deserialize()
            logging.debug("Returning permalink to bundle")
            return self._context.request.build_absolute_uri(
                reverse(
                    'dashboard_app.views.redirect_to_bundle',
                    kwargs={'content_sha1':bundle.content_sha1}))

    def get(self, content_sha1):
        """
        Name
        ----
        `get` (`content_sha1`)

        Description
        -----------<commit_msg>restore put() to the old api and add put_ex() with the new one<commit_after># Copyright (C) 2010 Linaro Limited
#
# Author: <NAME> <<EMAIL>>
#
# This file is part of Launch Control.
#
# Launch Control is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License version 3
# as published by the Free Software Foundation
#
# Launch Control 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 Affero General Public License
# along with Launch Control.  If not, see <http://www.gnu.org/licenses/>.

"""
XMP-RPC API
"""

import decimal
import logging
import xmlrpclib

from django.contrib.auth.models import User, Group
from django.core.urlresolvers import reverse
from django.db import IntegrityError, DatabaseError
from linaro_django_xmlrpc.models import (
    ExposedAPI,
    Mapper,
    xml_rpc_signature,
)

from dashboard_app import __version__
from dashboard_app.models import (
    Bundle,
    BundleStream,
    DataView,
)


class errors:
    """
    A namespace for error codes that may be returned by various XML-RPC
    methods. Where applicable existing status codes from HTTP protocol
    are reused
    """
    AUTH_FAILED = 100
    AUTH_BLOCKED = 101
    FORBIDDEN = 403
    NOT_FOUND = 404
    CONFLICT = 409
    INTERNAL_SERVER_ERROR = 500
    NOT_IMPLEMENTED = 501


class DashboardAPI(ExposedAPI):
    """
    Dashboard API object.

    All public methods are automatically exposed as XML-RPC methods
    """

    data_view_connection = DataView.get_connection()

    @xml_rpc_signature('str')
    def version(self):
        """
        Name
        ----
        `version` ()

        Description
        -----------
        Return dashboard server version. The version is a string with
        dots separating five components.

        The components are:
            1. major version
            2. minor version
            3. micro version
            4. release level
            5. serial

        See: http://docs.python.org/library/sys.html#sys.version_info

        Return value
        -------------
        Server version string
        """
        return ".".join(map(str, __version__))

    def _put(self, content, content_filename, pathname):
        try:
            logging.debug("Getting bundle stream")
            bundle_stream = BundleStream.objects.accessible_by_principal(self.user).get(pathname=pathname)
        except BundleStream.DoesNotExist:
            logging.debug("Bundle stream does not exists, aborting")
            raise xmlrpclib.Fault(errors.NOT_FOUND,
                    "Bundle stream not found")
        try:
            logging.debug("Creating bundle object")
            bundle = Bundle.objects.create_with_content(bundle_stream, self.user, content_filename, content)
        except (IntegrityError, ValueError) as exc:
            logging.debug("Raising xmlrpclib.Fault(errors.CONFLICT)")
            raise xmlrpclib.Fault(errors.CONFLICT, str(exc))
        except:
            logging.exception("big oops")
            raise
        else:   
            logging.debug("Deserializing bundle")
            bundle.deserialize()
            return bundle

    @xml_rpc_signature('str', 'str', 'str', 'str')
    def put(self, content, content_filename, pathname):
        """
        Name
        ----
        `put` (`content`, `content_filename`, `pathname`)

        Description
        -----------
        Upload a bundle to the server.

        Arguments
        ---------
        `content`: string
            Full text of the bundle. This *SHOULD* be a valid JSON
            document and it *SHOULD* match the "Dashboard Bundle Format
            1.0" schema. The SHA1 of the content *MUST* be unique or a
            ``Fault(409, "...")`` is raised. This is used to protect
            from simple duplicate submissions.
        `content_filename`: string
            Name of the file that contained the text of the bundle. The
            `content_filename` can be an arbitrary string and will be
            stored along with the content for reference.
        `pathname`: string
            Pathname of the bundle stream where a new bundle should
            be created and stored. This argument *MUST* designate a
            pre-existing bundle stream or a ``Fault(404, "...")`` exception
            is raised. In addition the user *MUST* have access
            permission to upload bundles there or a ``Fault(403, "...")``
            exception is raised. See below for access rules.

        Return value
        ------------
        If all goes well this function returns the SHA1 of the content.

        Exceptions raised
        -----------------
        404
            Either:

                - Bundle stream not found
                - Uploading to specified stream is not permitted
        409
            Duplicate bundle content

        Rules for bundle stream access
        ------------------------------
        The following rules govern bundle stream upload access rights:
            - all anonymous streams are accessible
            - personal streams are accessible to owners
            - team streams are accessible to team members

        """
        bundle = self._put(content, content_filename, pathname)
        logging.debug("Returning bundle SHA1")
        return bundle.content_sha1

    @xml_rpc_signature('str', 'str', 'str', 'str')
    def put_ex(self, content, content_filename, pathname):
        """
        Name
        ----
        `put` (`content`, `content_filename`, `pathname`)

        Description
        -----------
        Upload a bundle to the server.  A variant on put_ex that returns the
        URL of the bundle instead of its SHA1.

        Arguments
        ---------
        `content`: string
            Full text of the bundle. This *SHOULD* be a valid JSON
            document and it *SHOULD* match the "Dashboard Bundle Format
            1.0" schema. The SHA1 of the content *MUST* be unique or a
            ``Fault(409, "...")`` is raised. This is used to protect
            from simple duplicate submissions.
        `content_filename`: string
            Name of the file that contained the text of the bundle. The
            `content_filename` can be an arbitrary string and will be
            stored along with the content for reference.
        `pathname`: string
            Pathname of the bundle stream where a new bundle should
            be created and stored. This argument *MUST* designate a
            pre-existing bundle stream or a ``Fault(404, "...")`` exception
            is raised. In addition the user *MUST* have access
            permission to upload bundles there or a ``Fault(403, "...")``
            exception is raised. See below for access rules.

        Return value
        ------------
        If all goes well this function returns the full URL of the bundle.

        Exceptions raised
        -----------------
        404
            Either:

                - Bundle stream not found
                - Uploading to specified stream is not permitted
        409
            Duplicate bundle content

        Rules for bundle stream access
        ------------------------------
        The following rules govern bundle stream upload access rights:
            - all anonymous streams are accessible
            - personal streams are accessible to owners
            - team streams are accessible to team members

        """
        bundle = self._put(content, content_filename, pathname)
        logging.debug("Returning permalink to bundle")
        return self._context.request.build_absolute_uri(
            reverse(
                'dashboard_app.views.redirect_to_bundle',
                kwargs={'content_sha1':bundle.content_sha1}))

    def get(self, content_sha1):
        """
        Name
        ----
        `get` (`content_sha1`)

        Description
        -----------
{'fraction_non_alphanumeric': 0.09083688352949672, 'fraction_numerical': 0.009314751967651094, 'mean_word_length': 1.928737576654684, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 17}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1644885', 'n_tokens_mistral': 3556, 'n_tokens_neox': 3340, 'n_words': 1314}