<commit_before>"""Development helpers."""
import os
import re
from pathlib import Path
from shutil import rmtree
from textwrap import dedent
from typing import List, Tuple

import click
from plumbum import FG, RETCODE
from requests_html import HTMLSession

from clit.files import shell
from clit.ui import prompt

# Possible formats for tests:
# ___ test_name ___
# ___ Error on setup of test_name ___
# ___ test_name[Parameter] ___
TEST_NAMES_REGEX = re.compile(r"___ .*(test[^\[\] ]+)[\[\]A-Za-z]* ___")

PYCHARM_MACOS_APP_PATH = Path("/Applications/PyCharm.app/Contents/MacOS/pycharm")

@click.command()
@click.argument("files", nargs=-1)
def pycharm_cli(files):
    """Invoke PyCharm on the command line.

    If a file doesn't exist, call `which` to find out the real location.
    """
    full_paths: List[str] = []
    errors = False
    for possible_file in files:
        path = Path(possible_file).absolute()
        if path.is_file():
            full_paths.append(str(path))
        else:
            which_file = shell(f"which {possible_file}", quiet=True, return_lines=True)
            if which_file:
                full_paths.append(which_file[0])
            else:
                click.secho(f"File not found on $PATH: {possible_file}", fg="red")
                errors = True
    if full_paths:
        shell(f"{PYCHARM_MACOS_APP_PATH} {' '.join(full_paths)}")
    exit(1 if errors else 0)

@click.group()
def xpytest():
    """Extra commands for py.test."""
    pass

@xpytest.command()
@click.option("--delete", "-d", default=False, is_flag=True, help="Delete pytest directory first")
@click.option("--failed", "-f", default=False, is_flag=True, help="Run only failed tests")
@click.option("--count", "-c", default=0, help="Repeat the same test several times")
@click.option("--reruns", "-r", default=0, help="Re-run a failed test several times")
@click.argument("class_names_or_args", nargs=-1)
def run(delete: bool, failed: bool, count: int, reruns: int, class_names_or_args: Tuple[str]):
    """Run pytest with some shortcut options."""
    # Import locally, so we get an error only in this function, and not in other functions of this module.
    from plumbum.cmd import time as time_cmd, rm

    if delete:
        click.secho("Removing .pytest directory", fg="green", bold=True)
        rm["-rf", ".pytest"] & FG

    pytest_plus_args = ["pytest", "-vv", "--run-intermittent"]
    if reruns:
        pytest_plus_args.extend(["--reruns", str(reruns)])
    if failed:
        pytest_plus_args.append("--failed")

    if count:
        pytest_plus_args.extend(["--count", str(count)])

    if class_names_or_args:
        targets = []
        for name in class_names_or_args:
            if "." in name:
                parts = name.split(".")
                targets.append("{}.py::{}".format("/".join(parts[0:-1]), parts[-1]))
            else:
                # It might be an extra argument, let's just append it
                targets.append(name)
        pytest_plus_args.append("-s")
        pytest_plus_args.extend(targets)

    click.secho(f"Running tests: time {' '.join(pytest_plus_args)}", fg="green", bold=True)
    rv = time_cmd[pytest_plus_args] & RETCODE(FG=True)
    exit(rv)

@xpytest.command()
@click.option("-f", "--result-file", type=click.File())
@click.option("-j", "--jenkins-url", multiple=True)
@click.option("-s", "dont_capture", flag_value="-s", help="Don't capture output")
@click.pass_context
def results(ctx, result_file, jenkins_url: Tuple[str, ...], dont_capture):
    """Parse a file with the output of failed tests, then re-run only those failed tests."""
    if result_file:
        contents = result_file.read()
    elif jenkins_url:
        responses = []
        for url in set(jenkins_url):
            request = HTMLSession().get(url, auth=(os.environ["JENKINS_USERNAME"], os.environ["JENKINS_PASSWORD"]))
            responses.append(request.html.html)
        contents = "\n".join(responses)
    else:
        click.echo(ctx.get_help())
        return

    match = re.search(r"<title>(?P<error>.+Invalid password.+)</title>", contents)
    if match:
        click.secho(match.group("error"), fg="red")
        exit(1)

    all_tests = set(TEST_NAMES_REGEX.findall(contents))
    expression = " or ".join(all_tests)
    if not dont_capture:
        dont_capture = ""
    shell(f"pytest -vv {dont_capture} -k '{expression}'")

class PyPICommands:
    """Commands executed by this helper script."""

    # https://github.com/peritus/bumpversion
    BUMP_VERSION = "bumpversion {allow_dirty} {part}"
    BUMP_VERSION_DRY_RUN = f"{BUMP_VERSION} --dry-run --verbose"

    # https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-cli
    CHANGELOG = "conventional-changelog -i CHANGELOG.md -p angular"

    BUILD_SETUP_PY = "python setup.py sdist bdist_wheel --universal"

    # https://poetry.eustace.io/
    BUILD_POETRY = "poetry build"

    GIT_ADD_AND_COMMIT = "git add . && git commit -m'{}' --no-verify"
    GIT_PUSH = "git push"
    GIT_TAG = "git tag v{}"

    # https://github.com/pypa/twine
    # I tried using "poetry publish -u $TWINE_USERNAME -p $TWINE_PASSWORD"; the command didn't fail, but nothing was uploaded
    # I also tried setting $TWINE_USERNAME and $TWINE_PASSWORD on the environment, but then "twine upload" didn't work for some reason.
    TWINE_UPLOAD = "twine upload {repo} dist/*"

    # https://www.npmjs.com/package/conventional-github-releaser
    GITHUB_RELEASE = "conventional-github-releaser -p angular -v"

def remove_previous_builds() -> bool:
    """Remove previous builds under the /dist directory."""
    dist_dir = (Path(os.curdir) / "dist").resolve()
    if not dist_dir.exists():
        return False

    click.echo(f"Removing previous builds on {dist_dir}")
    try:
        rmtree(str(dist_dir))
    except OSError:
        return False
    return True

@click.group()
def pypi():
    """Commands to publish packages on PyPI."""
    pass

@pypi.command()
@click.option(
    "--part",
    "-p",
    default="minor",
    type=click.Choice(["major", "minor", "patch"]),
    help="Which part of the version number to bump",
)
@click.option(
    "--allow-dirty", "-d", default=False, is_flag=True, type=bool, help="Allow bumpversion to run on a dirty repo"
)
@click.pass_context
def full(ctx, part, allow_dirty: bool):
    """The full process to upload to PyPI (bump version, changelog, package, upload)."""
    # Recreate the setup.py
    ctx.invoke(setup_py)

    allow_dirty_option = "--allow-dirty" if allow_dirty else ""
    bump_dry_run_cmd = PyPICommands.BUMP_VERSION_DRY_RUN.format(allow_dirty=allow_dirty_option, part=part)
    bump = shell(bump_dry_run_cmd)
    if bump.returncode != 0:
        exit(bump.returncode)

    chosen_lines = shell(
        f'{bump_dry_run_cmd} 2>&1 | rg -e "would.+bump" -e "new version" | rg -o "\'(.+)\'"', return_lines=True
    )
    new_version = chosen_lines[0].strip("'")
    commit_message = chosen_lines[1].strip("'")
    click.echo(f"New version: {new_version}\nCommit message: {commit_message}")
    prompt("Were all versions correctly bumped?")

    shell(PyPICommands.BUMP_VERSION.format(allow_dirty=allow_dirty_option, part=part))
    shell(f"{PyPICommands.CHANGELOG} -s")

    remove_previous_builds()

    shell(PyPICommands.BUILD_POETRY)
    shell("ls -l dist")
    prompt("Was a dist/ directory created with a .tar.gz and a wheel?")

    shell("git diff")
    prompt("Is the git diff correct?")

    prompt(
        "Last confirmation (point of no return):\n"
        + "Changes will be committed, files will be uploaded to PyPI, a GitHub release will be created"
    )

    commands = (
        ("Add all files and commit (skipping hooks)", PyPICommands.GIT_ADD_AND_COMMIT.format(commit_message)),
        ("Push", PyPICommands.GIT_PUSH),
        (
            "Create the tag but don't push it yet (conventional-github-releaser will do that)",
            PyPICommands.GIT_TAG.format(new_version),
        ),
        ("Upload the files to TestPyPI via Twine", PyPICommands.TWINE_UPLOAD.format(repo="-r testpypi")),
        ("Upload the files to PyPI via Twine", PyPICommands.TWINE_UPLOAD.format(repo="")),
        ("Create a GitHub release", PyPICommands.GITHUB_RELEASE),
    )
    for header, command in commands:
        while True:
            click.secho(f"\n>>> {header}", fg="bright_white")
            if shell(command).returncode == 0:
                break
            prompt("Something went wrong, running the same command again.", fg="red")

    click.secho(f"The new version {new_version} was uploaded to PyPI! ✨ 🍰 ✨", fg="bright_white")

@pypi.command()
def changelog():
    """Preview the changelog."""
    shell(f"{PyPICommands.CHANGELOG} -u | less")

@click.group()
def xpoetry():
    """Extra commands for poetry."""
    pass

@xpoetry.command()
def setup_py():
    """Use poetry to generate a setup.py file from pyproject.toml."""
    remove_previous_builds()
    shell("poetry build")
    shell("tar -xvzf dist/*.gz --strip-components 1 */setup.py")
    shell("black setup.py")

    setup_py_path: Path = Path.cwd() / "setup.py"
    lines = setup_py_path.read_text().split("\n")
    lines.insert(
        1,
        dedent(
            '''
        """NOTICE: This file was generated automatically by the command: xpoetry setup-py."""
    '''
        ).strip(),
    )

    # Add a hint so mypy ignores the setup() line
    lines[-2] += "  # type: ignore"

    setup_py_path.write_text("\n".join(lines))
    click.secho("setup.py generated!", fg="green")
<commit_msg>fix: get correct Git commit message from bumpversion<commit_after>"""Development helpers."""
import os
import re
from pathlib import Path
from shutil import rmtree
from textwrap import dedent
from typing import List, Tuple

import click
from plumbum import FG, RETCODE
from requests_html import HTMLSession

from clit.files import shell
from clit.ui import prompt

# Possible formats for tests:
# ___ test_name ___
# ___ Error on setup of test_name ___
# ___ test_name[Parameter] ___
TEST_NAMES_REGEX = re.compile(r"___ .*(test[^\[\] ]+)[\[\]A-Za-z]* ___")

PYCHARM_MACOS_APP_PATH = Path("/Applications/PyCharm.app/Contents/MacOS/pycharm")

@click.command()
@click.argument("files", nargs=-1)
def pycharm_cli(files):
    """Invoke PyCharm on the command line.

    If a file doesn't exist, call `which` to find out the real location.
    """
    full_paths: List[str] = []
    errors = False
    for possible_file in files:
        path = Path(possible_file).absolute()
        if path.is_file():
            full_paths.append(str(path))
        else:
            which_file = shell(f"which {possible_file}", quiet=True, return_lines=True)
            if which_file:
                full_paths.append(which_file[0])
            else:
                click.secho(f"File not found on $PATH: {possible_file}", fg="red")
                errors = True
    if full_paths:
        shell(f"{PYCHARM_MACOS_APP_PATH} {' '.join(full_paths)}")
    exit(1 if errors else 0)

@click.group()
def xpytest():
    """Extra commands for py.test."""
    pass

@xpytest.command()
@click.option("--delete", "-d", default=False, is_flag=True, help="Delete pytest directory first")
@click.option("--failed", "-f", default=False, is_flag=True, help="Run only failed tests")
@click.option("--count", "-c", default=0, help="Repeat the same test several times")
@click.option("--reruns", "-r", default=0, help="Re-run a failed test several times")
@click.argument("class_names_or_args", nargs=-1)
def run(delete: bool, failed: bool, count: int, reruns: int, class_names_or_args: Tuple[str]):
    """Run pytest with some shortcut options."""
    # Import locally, so we get an error only in this function, and not in other functions of this module.
    from plumbum.cmd import time as time_cmd, rm

    if delete:
        click.secho("Removing .pytest directory", fg="green", bold=True)
        rm["-rf", ".pytest"] & FG

    pytest_plus_args = ["pytest", "-vv", "--run-intermittent"]
    if reruns:
        pytest_plus_args.extend(["--reruns", str(reruns)])
    if failed:
        pytest_plus_args.append("--failed")

    if count:
        pytest_plus_args.extend(["--count", str(count)])

    if class_names_or_args:
        targets = []
        for name in class_names_or_args:
            if "." in name:
                parts = name.split(".")
                targets.append("{}.py::{}".format("/".join(parts[0:-1]), parts[-1]))
            else:
                # It might be an extra argument, let's just append it
                targets.append(name)
        pytest_plus_args.append("-s")
        pytest_plus_args.extend(targets)

    click.secho(f"Running tests: time {' '.join(pytest_plus_args)}", fg="green", bold=True)
    rv = time_cmd[pytest_plus_args] & RETCODE(FG=True)
    exit(rv)

@xpytest.command()
@click.option("-f", "--result-file", type=click.File())
@click.option("-j", "--jenkins-url", multiple=True)
@click.option("-s", "dont_capture", flag_value="-s", help="Don't capture output")
@click.pass_context
def results(ctx, result_file, jenkins_url: Tuple[str, ...], dont_capture):
    """Parse a file with the output of failed tests, then re-run only those failed tests."""
    if result_file:
        contents = result_file.read()
    elif jenkins_url:
        responses = []
        for url in set(jenkins_url):
            request = HTMLSession().get(url, auth=(os.environ["JENKINS_USERNAME"], os.environ["JENKINS_PASSWORD"]))
            responses.append(request.html.html)
        contents = "\n".join(responses)
    else:
        click.echo(ctx.get_help())
        return

    match = re.search(r"<title>(?P<error>.+Invalid password.+)</title>", contents)
    if match:
        click.secho(match.group("error"), fg="red")
        exit(1)

    all_tests = set(TEST_NAMES_REGEX.findall(contents))
    expression = " or ".join(all_tests)
    if not dont_capture:
        dont_capture = ""
    shell(f"pytest -vv {dont_capture} -k '{expression}'")

class PyPICommands:
    """Commands executed by this helper script."""

    # https://github.com/peritus/bumpversion
    BUMP_VERSION = "bumpversion {allow_dirty} {part}"
    BUMP_VERSION_DRY_RUN = f"{BUMP_VERSION} --dry-run --verbose"

    # https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-cli
    CHANGELOG = "conventional-changelog -i CHANGELOG.md -p angular"

    BUILD_SETUP_PY = "python setup.py sdist bdist_wheel --universal"

    # https://poetry.eustace.io/
    BUILD_POETRY = "poetry build"

    GIT_ADD_AND_COMMIT = "git add . && git commit -m'{}' --no-verify"
    GIT_PUSH = "git push"
    GIT_TAG = "git tag v{}"

    # https://github.com/pypa/twine
    # I tried using "poetry publish -u $TWINE_USERNAME -p $TWINE_PASSWORD"; the command didn't fail, but nothing was uploaded
    # I also tried setting $TWINE_USERNAME and $TWINE_PASSWORD on the environment, but then "twine upload" didn't work for some reason.
    TWINE_UPLOAD = "twine upload {repo} dist/*"

    # https://www.npmjs.com/package/conventional-github-releaser
    GITHUB_RELEASE = "conventional-github-releaser -p angular -v"

def remove_previous_builds() -> bool:
    """Remove previous builds under the /dist directory."""
    dist_dir = (Path(os.curdir) / "dist").resolve()
    if not dist_dir.exists():
        return False

    click.echo(f"Removing previous builds on {dist_dir}")
    try:
        rmtree(str(dist_dir))
    except OSError:
        return False
    return True

@click.group()
def pypi():
    """Commands to publish packages on PyPI."""
    pass

@pypi.command()
@click.option(
    "--part",
    "-p",
    default="minor",
    type=click.Choice(["major", "minor", "patch"]),
    help="Which part of the version number to bump",
)
@click.option(
    "--allow-dirty", "-d", default=False, is_flag=True, type=bool, help="Allow bumpversion to run on a dirty repo"
)
@click.pass_context
def full(ctx, part, allow_dirty: bool):
    """The full process to upload to PyPI (bump version, changelog, package, upload)."""
    # Recreate the setup.py
    ctx.invoke(setup_py)

    allow_dirty_option = "--allow-dirty" if allow_dirty else ""
    bump_dry_run_cmd = PyPICommands.BUMP_VERSION_DRY_RUN.format(allow_dirty=allow_dirty_option, part=part)
    bump = shell(bump_dry_run_cmd)
    if bump.returncode != 0:
        exit(bump.returncode)

    chosen_lines = shell(
        f'{bump_dry_run_cmd} 2>&1 | rg -e "would commit to git.+bump" -e "new version" | rg -o "\'(.+)\'"',
        return_lines=True,
    )
    new_version = chosen_lines[0].strip("'")
    commit_message = chosen_lines[1].strip("'")
    click.echo(f"New version: {new_version}\nCommit message: {commit_message}")
    prompt("Were all versions correctly displayed?")

    shell(PyPICommands.BUMP_VERSION.format(allow_dirty=allow_dirty_option, part=part))
    shell(f"{PyPICommands.CHANGELOG} -s")

    remove_previous_builds()

    shell(PyPICommands.BUILD_POETRY)
    shell("ls -l dist")
    prompt("Was a dist/ directory created with a .tar.gz and a wheel?")

    shell("git diff")
    prompt("Is the git diff correct?")

    prompt(
        "Last confirmation (point of no return):\n"
        + "Changes will be committed, files will be uploaded to PyPI, a GitHub release will be created"
    )

    commands = (
        ("Add all files and commit (skipping hooks)", PyPICommands.GIT_ADD_AND_COMMIT.format(commit_message)),
        ("Push", PyPICommands.GIT_PUSH),
        (
            "Create the tag but don't push it yet (conventional-github-releaser will do that)",
            PyPICommands.GIT_TAG.format(new_version),
        ),
        ("Upload the files to TestPyPI via Twine", PyPICommands.TWINE_UPLOAD.format(repo="-r testpypi")),
        ("Upload the files to PyPI via Twine", PyPICommands.TWINE_UPLOAD.format(repo="")),
        ("Create a GitHub release", PyPICommands.GITHUB_RELEASE),
    )
    for header, command in commands:
        while True:
            click.secho(f"\n>>> {header}", fg="bright_white")
            if shell(command).returncode == 0:
                break
            prompt("Something went wrong, running the same command again.", fg="red")

    click.secho(f"The new version {new_version} was uploaded to PyPI! ✨ 🍰 ✨", fg="bright_white")

@pypi.command()
def changelog():
    """Preview the changelog."""
    shell(f"{PyPICommands.CHANGELOG} -u | less")

@click.group()
def xpoetry():
    """Extra commands for poetry."""
    pass

@xpoetry.command()
def setup_py():
    """Use poetry to generate a setup.py file from pyproject.toml."""
    remove_previous_builds()
    shell("poetry build")
    shell("tar -xvzf dist/*.gz --strip-components 1 */setup.py")
    shell("black setup.py")

    setup_py_path: Path = Path.cwd() / "setup.py"
    lines = setup_py_path.read_text().split("\n")
    lines.insert(
        1,
        dedent(
            '''
        """NOTICE: This file was generated automatically by the command: xpoetry setup-py."""
    '''
        ).strip(),
    )

    # Add a hint so mypy ignores the setup() line
    lines[-2] += "  # type: ignore"

    setup_py_path.write_text("\n".join(lines))
    click.secho("setup.py generated!", fg="green")
<|endoftext|>


<commit_before># Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals

import base64
import binascii
import json

from six.moves.urllib.parse import urlencode, urlparse

import frappe
import frappe.client
import frappe.handler
from frappe import _
from frappe.utils.response import build_response

def handle():
	"""
	Handler for `/api` methods

	### Examples:

	`/api/method/{methodname}` will call a whitelisted method

	`/api/resource/{doctype}` will query a table
		examples:
		- `?fields=["name", "owner"]`
		- `?filters=[["Task", "name", "like", "%005"]]`
		- `?limit_start=0`
		- `?limit_page_length=20`

	`/api/resource/{doctype}/{name}` will point to a resource
		`GET` will return doclist
		`POST` will insert
		`PUT` will update
		`DELETE` will delete

	`/api/resource/{doctype}/{name}?run_method={method}` will run a whitelisted controller method
	"""

	validate_auth()

	parts = frappe.request.path[1:].split("/",3)
	call = doctype = name = None

	if len(parts) > 1:
		call = parts[1]

	if len(parts) > 2:
		doctype = parts[2]

	if len(parts) > 3:
		name = parts[3]

	if call=="method":
		frappe.local.form_dict.cmd = doctype
		return frappe.handler.handle()

	elif call=="resource":
		if "run_method" in frappe.local.form_dict:
			method = frappe.local.form_dict.pop("run_method")
			doc = frappe.get_doc(doctype, name)
			doc.is_whitelisted(method)

			if frappe.local.request.method=="GET":
				if not doc.has_permission("read"):
					frappe.throw(_("Not permitted"), frappe.PermissionError)
				frappe.local.response.update({"data": doc.run_method(method, **frappe.local.form_dict)})

			if frappe.local.request.method=="POST":
				if not doc.has_permission("write"):
					frappe.throw(_("Not permitted"), frappe.PermissionError)

				frappe.local.response.update({"data": doc.run_method(method, **frappe.local.form_dict)})
				frappe.db.commit()

		else:
			if name:
				if frappe.local.request.method=="GET":
					doc = frappe.get_doc(doctype, name)
					if not doc.has_permission("read"):
						raise frappe.PermissionError
					frappe.local.response.update({"data": doc})

				if frappe.local.request.method=="PUT":
					data = get_request_form_data()

					doc = frappe.get_doc(doctype, name)

					if "flags" in data:
						del data["flags"]

					# Not checking permissions here because it's checked in doc.save
					doc.update(data)

					frappe.local.response.update({
						"data": doc.save().as_dict()
					})

					if doc.parenttype and doc.parent:
						frappe.get_doc(doc.parenttype, doc.parent).save()

					frappe.db.commit()

				if frappe.local.request.method=="DELETE":
					# Not checking permissions here because it's checked in delete_doc
					frappe.delete_doc(doctype, name, ignore_missing=False)
					frappe.local.response.http_status_code = 202
					frappe.local.response.message = "ok"
					frappe.db.commit()

			elif doctype:
				if frappe.local.request.method=="GET":
					if frappe.local.form_dict.get('fields'):
						frappe.local.form_dict['fields'] = json.loads(frappe.local.form_dict['fields'])
					frappe.local.form_dict.setdefault('limit_page_length', 20)
					frappe.local.response.update({
						"data":  frappe.call(frappe.client.get_list,
							doctype, **frappe.local.form_dict)})

				if frappe.local.request.method == "POST":
					data = get_request_form_data()
					data.update({
						"doctype": doctype
					})
					frappe.local.response.update({
						"data": frappe.get_doc(data).insert().as_dict()
					})
					frappe.db.commit()
			else:
				raise frappe.DoesNotExistError

	else:
		raise frappe.DoesNotExistError

	return build_response("json")

def get_request_form_data():
	if frappe.local.form_dict.data is None:
		data = json.loads(frappe.safe_decode(frappe.local.request.get_data()))
	else:
		data = frappe.local.form_dict.data
		if isinstance(data, string_types):
			data = json.loads(frappe.local.form_dict.data)

	return data

def validate_auth():
	if frappe.get_request_header("Authorization") is None:
		return

	VALID_AUTH_PREFIX_TYPES = ['basic', 'bearer', 'token']
	VALID_AUTH_PREFIX_STRING = ", ".join(VALID_AUTH_PREFIX_TYPES).title()

	authorization_header = frappe.get_request_header("Authorization", str()).split(" ")
	authorization_type = authorization_header[0].lower()

	if len(authorization_header) == 1:
		frappe.throw(_('Invalid Authorization headers, add a token with a prefix from one of the following: {0}.'.format(VALID_AUTH_PREFIX_STRING)), frappe.InvalidAuthorizationHeader)

	if authorization_type == "bearer":
		validate_oauth(authorization_header)
	elif authorization_type in VALID_AUTH_PREFIX_TYPES:
		validate_auth_via_api_keys(authorization_header)
	else:
		frappe.throw(_('Invalid Authorization Type {0}, must be one of {1}.'.format(authorization_type, VALID_AUTH_PREFIX_STRING)), frappe.InvalidAuthorizationPrefix)

def validate_oauth(authorization_header):
	"""
	Authenticate request using OAuth and set session user

	Args:
		authorization_header (list of str): The 'Authorization' header containing the prefix and token
	"""

	from frappe.oauth import get_url_delimiter
	from frappe.integrations.oauth2 import get_oauth_server

	form_dict = frappe.local.form_dict
	token = authorization_header[1]
	req = frappe.request
	parsed_url = urlparse(req.url)
	access_token = {"access_token": token}
	uri = parsed_url.scheme + "://" + parsed_url.netloc + parsed_url.path + "?" + urlencode(access_token)
	http_method = req.method
	body = req.get_data()
	headers = req.headers

	try:
		required_scopes = frappe.db.get_value("OAuth Bearer Token", token, "scopes").split(get_url_delimiter())
	except AttributeError:
		frappe.throw(_("Invalid Bearer token, please provide a valid access token with prefix 'Bearer'."), frappe.InvalidAuthorizationToken)

	valid, oauthlib_request = get_oauth_server().verify_request(uri, http_method, body, headers, required_scopes)

	if valid:
		frappe.set_user(frappe.db.get_value("OAuth Bearer Token", token, "user"))
		frappe.local.form_dict = form_dict

def validate_auth_via_api_keys(authorization_header):
	"""
	Authenticate request using API keys and set session user

	Args:
		authorization_header (list of str): The 'Authorization' header containing the prefix and token
	"""

	try:
		auth_type, auth_token = authorization_header
		authorization_source = frappe.get_request_header("Frappe-Authorization-Source")
		if auth_type.lower() == 'basic':
			api_key, api_secret = frappe.safe_decode(base64.b64decode(auth_token)).split(":")
			validate_api_key_secret(api_key, api_secret, authorization_source)
		elif auth_type.lower() == 'token':
			api_key, api_secret = auth_token.split(":")
			validate_api_key_secret(api_key, api_secret, authorization_source)
	except binascii.Error:
		frappe.throw(_("Failed to decode token, please provide a valid base64-encoded token."), frappe.InvalidAuthorizationToken)
	except (AttributeError, TypeError, ValueError):
		frappe.throw(_("Invalid token, please provide a valid token with prefix 'Basic' or 'Token'."), frappe.InvalidAuthorizationToken)

def validate_api_key_secret(api_key, api_secret):
	user = frappe.db.get_value(
		doctype="User",
		filters={"api_key": api_key},
		fieldname=['name']
	)
	form_dict = frappe.local.form_dict
	user_secret = frappe.utils.password.get_decrypted_password ("User", user, fieldname='api_secret')
	if api_secret == user_secret:
		frappe.set_user(user)
		frappe.local.form_dict = form_dict
<commit_msg>fix: revert import removal + remove extra variable<commit_after># Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals

import base64
import binascii
import json

from six import string_types
from six.moves.urllib.parse import urlencode, urlparse

import frappe
import frappe.client
import frappe.handler
from frappe import _
from frappe.utils.response import build_response

def handle():
	"""
	Handler for `/api` methods

	### Examples:

	`/api/method/{methodname}` will call a whitelisted method

	`/api/resource/{doctype}` will query a table
		examples:
		- `?fields=["name", "owner"]`
		- `?filters=[["Task", "name", "like", "%005"]]`
		- `?limit_start=0`
		- `?limit_page_length=20`

	`/api/resource/{doctype}/{name}` will point to a resource
		`GET` will return doclist
		`POST` will insert
		`PUT` will update
		`DELETE` will delete

	`/api/resource/{doctype}/{name}?run_method={method}` will run a whitelisted controller method
	"""

	validate_auth()

	parts = frappe.request.path[1:].split("/",3)
	call = doctype = name = None

	if len(parts) > 1:
		call = parts[1]

	if len(parts) > 2:
		doctype = parts[2]

	if len(parts) > 3:
		name = parts[3]

	if call=="method":
		frappe.local.form_dict.cmd = doctype
		return frappe.handler.handle()

	elif call=="resource":
		if "run_method" in frappe.local.form_dict:
			method = frappe.local.form_dict.pop("run_method")
			doc = frappe.get_doc(doctype, name)
			doc.is_whitelisted(method)

			if frappe.local.request.method=="GET":
				if not doc.has_permission("read"):
					frappe.throw(_("Not permitted"), frappe.PermissionError)
				frappe.local.response.update({"data": doc.run_method(method, **frappe.local.form_dict)})

			if frappe.local.request.method=="POST":
				if not doc.has_permission("write"):
					frappe.throw(_("Not permitted"), frappe.PermissionError)

				frappe.local.response.update({"data": doc.run_method(method, **frappe.local.form_dict)})
				frappe.db.commit()

		else:
			if name:
				if frappe.local.request.method=="GET":
					doc = frappe.get_doc(doctype, name)
					if not doc.has_permission("read"):
						raise frappe.PermissionError
					frappe.local.response.update({"data": doc})

				if frappe.local.request.method=="PUT":
					data = get_request_form_data()

					doc = frappe.get_doc(doctype, name)

					if "flags" in data:
						del data["flags"]

					# Not checking permissions here because it's checked in doc.save
					doc.update(data)

					frappe.local.response.update({
						"data": doc.save().as_dict()
					})

					if doc.parenttype and doc.parent:
						frappe.get_doc(doc.parenttype, doc.parent).save()

					frappe.db.commit()

				if frappe.local.request.method=="DELETE":
					# Not checking permissions here because it's checked in delete_doc
					frappe.delete_doc(doctype, name, ignore_missing=False)
					frappe.local.response.http_status_code = 202
					frappe.local.response.message = "ok"
					frappe.db.commit()

			elif doctype:
				if frappe.local.request.method=="GET":
					if frappe.local.form_dict.get('fields'):
						frappe.local.form_dict['fields'] = json.loads(frappe.local.form_dict['fields'])
					frappe.local.form_dict.setdefault('limit_page_length', 20)
					frappe.local.response.update({
						"data":  frappe.call(frappe.client.get_list,
							doctype, **frappe.local.form_dict)})

				if frappe.local.request.method == "POST":
					data = get_request_form_data()
					data.update({
						"doctype": doctype
					})
					frappe.local.response.update({
						"data": frappe.get_doc(data).insert().as_dict()
					})
					frappe.db.commit()
			else:
				raise frappe.DoesNotExistError

	else:
		raise frappe.DoesNotExistError

	return build_response("json")

def get_request_form_data():
	if frappe.local.form_dict.data is None:
		data = json.loads(frappe.safe_decode(frappe.local.request.get_data()))
	else:
		data = frappe.local.form_dict.data
		if isinstance(data, string_types):
			data = json.loads(frappe.local.form_dict.data)

	return data

def validate_auth():
	if frappe.get_request_header("Authorization") is None:
		return

	VALID_AUTH_PREFIX_TYPES = ['basic', 'bearer', 'token']
	VALID_AUTH_PREFIX_STRING = ", ".join(VALID_AUTH_PREFIX_TYPES).title()

	authorization_header = frappe.get_request_header("Authorization", str()).split(" ")
	authorization_type = authorization_header[0].lower()

	if len(authorization_header) == 1:
		frappe.throw(_('Invalid Authorization headers, add a token with a prefix from one of the following: {0}.'.format(VALID_AUTH_PREFIX_STRING)), frappe.InvalidAuthorizationHeader)

	if authorization_type == "bearer":
		validate_oauth(authorization_header)
	elif authorization_type in VALID_AUTH_PREFIX_TYPES:
		validate_auth_via_api_keys(authorization_header)
	else:
		frappe.throw(_('Invalid Authorization Type {0}, must be one of {1}.'.format(authorization_type, VALID_AUTH_PREFIX_STRING)), frappe.InvalidAuthorizationPrefix)

def validate_oauth(authorization_header):
	"""
	Authenticate request using OAuth and set session user

	Args:
		authorization_header (list of str): The 'Authorization' header containing the prefix and token
	"""

	from frappe.oauth import get_url_delimiter
	from frappe.integrations.oauth2 import get_oauth_server

	form_dict = frappe.local.form_dict
	token = authorization_header[1]
	req = frappe.request
	parsed_url = urlparse(req.url)
	access_token = {"access_token": token}
	uri = parsed_url.scheme + "://" + parsed_url.netloc + parsed_url.path + "?" + urlencode(access_token)
	http_method = req.method
	body = req.get_data()
	headers = req.headers

	try:
		required_scopes = frappe.db.get_value("OAuth Bearer Token", token, "scopes").split(get_url_delimiter())
	except AttributeError:
		frappe.throw(_("Invalid Bearer token, please provide a valid access token with prefix 'Bearer'."), frappe.InvalidAuthorizationToken)

	valid, oauthlib_request = get_oauth_server().verify_request(uri, http_method, body, headers, required_scopes)

	if valid:
		frappe.set_user(frappe.db.get_value("OAuth Bearer Token", token, "user"))
		frappe.local.form_dict = form_dict

def validate_auth_via_api_keys(authorization_header):
	"""
	Authenticate request using API keys and set session user

	Args:
		authorization_header (list of str): The 'Authorization' header containing the prefix and token
	"""

	try:
		auth_type, auth_token = authorization_header
		if auth_type.lower() == 'basic':
			api_key, api_secret = frappe.safe_decode(base64.b64decode(auth_token)).split(":")
			validate_api_key_secret(api_key, api_secret)
		elif auth_type.lower() == 'token':
			api_key, api_secret = auth_token.split(":")
			validate_api_key_secret(api_key, api_secret)
	except binascii.Error:
		frappe.throw(_("Failed to decode token, please provide a valid base64-encoded token."), frappe.InvalidAuthorizationToken)
	except (AttributeError, TypeError, ValueError):
		frappe.throw(_("Invalid token, please provide a valid token with prefix 'Basic' or 'Token'."), frappe.InvalidAuthorizationToken)

def validate_api_key_secret(api_key, api_secret):
	user = frappe.db.get_value(
		doctype="User",
		filters={"api_key": api_key},
		fieldname=['name']
	)
	form_dict = frappe.local.form_dict
	user_secret = frappe.utils.password.get_decrypted_password("User", user, fieldname='api_secret')
	if api_secret == user_secret:
		frappe.set_user(user)
		frappe.local.form_dict = form_dict
<|endoftext|>


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

from openerp import api, fields, models, _
import openerp.addons.decimal_precision as dp

from openerp.exceptions import UserError

class DeliveryDistributionList(models.Model):
    _name = 'delivery.distribution.list'

    name = fields.Char(string="Name")
    distribution_date = fields.Date(string='Distribution Date', readonly=True, required=True, index=True, states={'draft': [('readonly', False)]})
    create_date = fields.Date(string='Creation Date', readonly=True, help="Date on which distribution list is created.", copy=False, default=fields.Datetime.now)

    user_id = fields.Many2one('res.users', string='Distribution responsible', index=True, copy=False, default=lambda self: self.env.user)
    product_id = fields.Many2one('product.template', string='Product', required=True, readonly=True, states={'draft': [('readonly', False)]})
    distribution_lines = fields.One2many('delivery.distribution.line','distribution_list_id', string="Distribution lines", copy=False)

    state = fields.Selection([
        ('draft', 'Draft'),
        ('validated', 'Validated'),
        ('sale', 'Sale Order'),
        ('sale_sent', 'Sale order sent'),
        ('invoiced', 'Invoiced'),
        ('invoice_validated', 'Invoice validated'),
        ('invoice_sent', 'Invoice sent'),
        ('done', 'Done'),
        ('cancelled', 'Cancelled'),
        ], string='State', readonly=True, copy=False, default='draft')

    @api.one
    def action_validate(self):
        self.distribution_lines.write({'state':'validated'})
        self.state = 'validated'

    @api.one
    def action_draft(self):
        self.distribution_lines.write({'state':'draft'})
        self.state = 'draft'

    @api.one
    def action_done(self):
        self.state = 'done'

    @api.one
    def action_sale(self):
        self.distribution_lines.generate_sale_order()
        self.state = 'sale'

    @api.one
    def action_send_sale_order(self):
        self.distribution_lines.send_sale_order()
        self.state = 'sale_sent'

    @api.one
    def action_invoice(self):
        self.distribution_lines.invoice_sale_order()
        self.state = 'invoiced'

    @api.one
    def action_validate_invoice(self):
        self.distribution_lines.validate_invoice()
        self.state = 'invoice_validated'

    @api.one
    def action_send_invoice(self):
        self.distribution_lines.send_invoice()
        self.state = 'invoice_sent'

    @api.one
    def action_cancel(self):
        self.state = 'cancelled'

    @api.one
    def generate_distribution_list(self):
        deposit_points = self.env['res.partner'].search([('deposit_point','=',True)])

        #delete existing lines if any
        if self.state == 'draft':
            self.distribution_lines.unlink()

            vals = {'distribution_list_id':self.id, 'product_id':self.product_id.id}

            for deposit_point in deposit_points:
                if deposit_point.quantity_to_deliver > 0.0:
                    vals['partner_id'] = deposit_point.id
                    vals['carrier_id'] = deposit_point.carrier_id.id
                    vals['ordered_qty'] = deposit_point.quantity_to_deliver
                    vals['delivered_qty'] = deposit_point.quantity_to_deliver
                    self.env['delivery.distribution.line'].create(vals)

    @api.multi
    def unlink(self):
        for distri_list in self:
            if distri_list.state != 'draft':
                raise UserError(_('It is forbidden to modify a distribution list which is not in draft status'))
            super(DeliveryDistributionList,self).unlink()

class DeliveryDistributionLine(models.Model):
    _name = 'delivery.distribution.line'

    _order = 'partner_id, date'

    @api.multi
    def _compute_sold_qty(self):
        for line in self:
            line.sold_qty = line.delivered_qty - line.returned_qty

    distribution_list_id = fields.Many2one('delivery.distribution.list', string="Distribution list", required=True)
    partner_id = fields.Many2one('res.partner', string="Customer", domain=[('deposit_point','=',True)])
    product_id = fields.Many2one('product.template', string='Product', required=True)
    date = fields.Date(string='Creation Date', readonly=True, help="Date on which distribution line is created.", default=fields.Datetime.now)
    product_uom = fields.Many2one(related='product_id.uom_id', string='Unit of Measure', readonly=True)
    ordered_qty = fields.Float(string="Quantity Ordered", digits=dp.get_precision('Product Unit of Measure'), required=True)
    delivered_qty = fields.Float(string="Quantity Delivered", digits=dp.get_precision('Product Unit of Measure'), default=0.0, required=True)
    returned_qty = fields.Float(string="Quantity Returned", digits=dp.get_precision('Product Unit of Measure'), default=0.0, required=True)
    sold_qty = fields.Float(string="Quantity Sold", digits=dp.get_precision('Product Unit of Measure'), compute='_compute_sold_qty')
    carrier_id = fields.Many2one('res.partner', string="Assigned carrier", readonly=True)

    state = fields.Selection([
        ('draft', 'Draft'),
        ('validated', 'Validated'),
        ('sale', 'Sale Order'),
        ('sale_sent', 'Sale order sent'),
        ('invoiced', 'Invoiced'),
        ('invoice_validated', 'Invoice validated'),
        ('invoice_sent', 'Invoice sent'),
        ('cancelled', 'Cancelled'),
        ], string='State', readonly=True, copy=False, index=True, default='draft')

    sale_order = fields.Many2one('sale.order', string="Sale Order", readonly=True)
#    invoices = fields.One2many('account.invoice','distribution_line_id', string="Invoice", readonly=True)

    @api.one
    def unlink(self):
        if self.state != 'draft':
            raise UserError(_('It is forbidden to modify a distribution list which is not in draft status'))
        super(DeliveryDistributionLine,self).unlink()

    @api.multi
    def action_validate(self):
        for line in self:
            if line == 'draft':
                line.state = 'validated'

    @api.multi
    def action_draft(self):
        for line in self:
            if line == 'validated':
                line.state = 'draft'

    @api.multi
    def generate_sale_order(self):
        sale_order_obj = self.env['sale.order']
        order_line_obj = self.env['sale.order.line']
        for line in self:
            vals = {
                'partner_id':line.partner_id.id,
                'distribution_list_id':self.distribution_list_id.id,
                'carrier_id':self.carrier_id,
            }
            order_id = sale_order_obj.create(vals)
            vals_line = {
                'product_id':line.product_id.id,
                'product_uom_qty':line.delivered_qty,
                'product_uom':line.product_uom.id,
                'order_id':order_id.id
            }
            order_line_obj.create(vals_line)
            line.sale_order = order_id
            order_id.action_confirm()
            line.state = 'sale'

    @api.multi
    def send_sale_order(self):
        ir_model_data = self.env['ir.model.data']
        mail_template_obj = self.env['mail.template']
        mail_template_id = ir_model_data.get_object_reference('sale', 'email_template_edi_sale')[1]
        mail_template = mail_template_obj.browse(mail_template_id)
        for line in self:
            mail_template.send_mail(line.sale_order.id, False)
            line.state = 'sale_sent'

    @api.multi
    def invoice_sale_order(self):
        for line in self:
            if line.state in ['sale','sale_sent']:
                picking_ids = line.sale_order.picking_ids.ids
                pickings = self.env['stock.picking'].search([('id','in',picking_ids),
                                                  ('origin','=',line.sale_order.name)])
                for picking in pickings:
                    if picking.state not in ['cancel','done']:
                        if picking.state != 'assigned':
                            picking.recheck_availability()
                        for pack_operation in picking.pack_operation_ids:
                            if pack_operation.product_id.id == line.product_id.product_variant_ids.id:
                                pack_operation.qty_done = line.sold_qty
                                if line.sold_qty < line.delivered_qty:
                                    pack_operation.product_qty = line.sold_qty
                        picking.do_transfer()
                        if line.sold_qty < line.delivered_qty:
                            backorder_pick = self.env['stock.picking'].search([('backorder_id', '=', picking.id)])
                            backorder_pick.action_cancel()
                            picking.message_post(body=_("Back order %s cancelled.") % (backorder_pick.name))
                line.sale_order.action_invoice_create()
                line.state = 'invoiced'

    @api.multi
    def validate_invoice(self):
        for line in self:
            if line.state == 'invoiced':
                line.sale_order.invoice_ids.signal_workflow('invoice_open')
                line.state = 'invoice_validated'

    @api.multi
    def send_invoice(self):
        mail_template = self.env.ref('account.email_template_edi_invoice', False)
        for line in self:
            if line.state == 'invoice_validated':
                mail_template.send_mail(line.sale_order.invoice_ids.id, False)
                line.state = 'sale_sent'<commit_msg>[FIX] wrong use of self instead of line<commit_after># -*- coding: utf-8 -*-

from openerp import api, fields, models, _
import openerp.addons.decimal_precision as dp

from openerp.exceptions import UserError

class DeliveryDistributionList(models.Model):
    _name = 'delivery.distribution.list'

    name = fields.Char(string="Name")
    distribution_date = fields.Date(string='Distribution Date', readonly=True, required=True, index=True, states={'draft': [('readonly', False)]})
    create_date = fields.Date(string='Creation Date', readonly=True, help="Date on which distribution list is created.", copy=False, default=fields.Datetime.now)

    user_id = fields.Many2one('res.users', string='Distribution responsible', index=True, copy=False, default=lambda self: self.env.user)
    product_id = fields.Many2one('product.template', string='Product', required=True, readonly=True, states={'draft': [('readonly', False)]})
    distribution_lines = fields.One2many('delivery.distribution.line','distribution_list_id', string="Distribution lines", copy=False)

    state = fields.Selection([
        ('draft', 'Draft'),
        ('validated', 'Validated'),
        ('sale', 'Sale Order'),
        ('sale_sent', 'Sale order sent'),
        ('invoiced', 'Invoiced'),
        ('invoice_validated', 'Invoice validated'),
        ('invoice_sent', 'Invoice sent'),
        ('done', 'Done'),
        ('cancelled', 'Cancelled'),
        ], string='State', readonly=True, copy=False, default='draft')

    @api.one
    def action_validate(self):
        self.distribution_lines.write({'state':'validated'})
        self.state = 'validated'

    @api.one
    def action_draft(self):
        self.distribution_lines.write({'state':'draft'})
        self.state = 'draft'

    @api.one
    def action_done(self):
        self.state = 'done'

    @api.one
    def action_sale(self):
        self.distribution_lines.generate_sale_order()
        self.state = 'sale'

    @api.one
    def action_send_sale_order(self):
        self.distribution_lines.send_sale_order()
        self.state = 'sale_sent'

    @api.one
    def action_invoice(self):
        self.distribution_lines.invoice_sale_order()
        self.state = 'invoiced'

    @api.one
    def action_validate_invoice(self):
        self.distribution_lines.validate_invoice()
        self.state = 'invoice_validated'

    @api.one
    def action_send_invoice(self):
        self.distribution_lines.send_invoice()
        self.state = 'invoice_sent'

    @api.one
    def action_cancel(self):
        self.state = 'cancelled'

    @api.one
    def generate_distribution_list(self):
        deposit_points = self.env['res.partner'].search([('deposit_point','=',True)])

        #delete existing lines if any
        if self.state == 'draft':
            self.distribution_lines.unlink()

            vals = {'distribution_list_id':self.id, 'product_id':self.product_id.id}

            for deposit_point in deposit_points:
                if deposit_point.quantity_to_deliver > 0.0:
                    vals['partner_id'] = deposit_point.id
                    vals['carrier_id'] = deposit_point.carrier_id.id
                    vals['ordered_qty'] = deposit_point.quantity_to_deliver
                    vals['delivered_qty'] = deposit_point.quantity_to_deliver
                    self.env['delivery.distribution.line'].create(vals)

    @api.multi
    def unlink(self):
        for distri_list in self:
            if distri_list.state != 'draft':
                raise UserError(_('It is forbidden to modify a distribution list which is not in draft status'))
            super(DeliveryDistributionList,self).unlink()

class DeliveryDistributionLine(models.Model):
    _name = 'delivery.distribution.line'

    _order = 'partner_id, date'

    @api.multi
    def _compute_sold_qty(self):
        for line in self:
            line.sold_qty = line.delivered_qty - line.returned_qty

    distribution_list_id = fields.Many2one('delivery.distribution.list', string="Distribution list", required=True)
    partner_id = fields.Many2one('res.partner', string="Customer", domain=[('deposit_point','=',True)])
    product_id = fields.Many2one('product.template', string='Product', required=True)
    date = fields.Date(string='Creation Date', readonly=True, help="Date on which distribution line is created.", default=fields.Datetime.now)
    product_uom = fields.Many2one(related='product_id.uom_id', string='Unit of Measure', readonly=True)
    ordered_qty = fields.Float(string="Quantity Ordered", digits=dp.get_precision('Product Unit of Measure'), required=True)
    delivered_qty = fields.Float(string="Quantity Delivered", digits=dp.get_precision('Product Unit of Measure'), default=0.0, required=True)
    returned_qty = fields.Float(string="Quantity Returned", digits=dp.get_precision('Product Unit of Measure'), default=0.0, required=True)
    sold_qty = fields.Float(string="Quantity Sold", digits=dp.get_precision('Product Unit of Measure'), compute='_compute_sold_qty')
    carrier_id = fields.Many2one('res.partner', string="Assigned carrier", readonly=True)

    state = fields.Selection([
        ('draft', 'Draft'),
        ('validated', 'Validated'),
        ('sale', 'Sale Order'),
        ('sale_sent', 'Sale order sent'),
        ('invoiced', 'Invoiced'),
        ('invoice_validated', 'Invoice validated'),
        ('invoice_sent', 'Invoice sent'),
        ('cancelled', 'Cancelled'),
        ], string='State', readonly=True, copy=False, index=True, default='draft')

    sale_order = fields.Many2one('sale.order', string="Sale Order", readonly=True)
#    invoices = fields.One2many('account.invoice','distribution_line_id', string="Invoice", readonly=True)

    @api.one
    def unlink(self):
        if self.state != 'draft':
            raise UserError(_('It is forbidden to modify a distribution list which is not in draft status'))
        super(DeliveryDistributionLine,self).unlink()

    @api.multi
    def action_validate(self):
        for line in self:
            if line == 'draft':
                line.state = 'validated'

    @api.multi
    def action_draft(self):
        for line in self:
            if line == 'validated':
                line.state = 'draft'

    @api.multi
    def generate_sale_order(self):
        sale_order_obj = self.env['sale.order']
        order_line_obj = self.env['sale.order.line']
        for line in self:
            vals = {
                'partner_id':line.partner_id.id,
                'distribution_list_id':line.distribution_list_id.id,
                'carrier_id':line.carrier_id.id,
            }
            order_id = sale_order_obj.create(vals)
            vals_line = {
                'product_id':line.product_id.id,
                'product_uom_qty':line.delivered_qty,
                'product_uom':line.product_uom.id,
                'order_id':order_id.id
            }
            order_line_obj.create(vals_line)
            line.sale_order = order_id
            order_id.action_confirm()
            line.state = 'sale'

    @api.multi
    def send_sale_order(self):
        ir_model_data = self.env['ir.model.data']
        mail_template_obj = self.env['mail.template']
        mail_template_id = ir_model_data.get_object_reference('sale', 'email_template_edi_sale')[1]
        mail_template = mail_template_obj.browse(mail_template_id)
        for line in self:
            mail_template.send_mail(line.sale_order.id, False)
            line.state = 'sale_sent'

    @api.multi
    def invoice_sale_order(self):
        for line in self:
            if line.state in ['sale','sale_sent']:
                picking_ids = line.sale_order.picking_ids.ids
                pickings = self.env['stock.picking'].search([('id','in',picking_ids),
                                                  ('origin','=',line.sale_order.name)])
                for picking in pickings:
                    if picking.state not in ['cancel','done']:
                        if picking.state != 'assigned':
                            picking.recheck_availability()
                        for pack_operation in picking.pack_operation_ids:
                            if pack_operation.product_id.id == line.product_id.product_variant_ids.id:
                                pack_operation.qty_done = line.sold_qty
                                if line.sold_qty < line.delivered_qty:
                                    pack_operation.product_qty = line.sold_qty
                        picking.do_transfer()
                        if line.sold_qty < line.delivered_qty:
                            backorder_pick = self.env['stock.picking'].search([('backorder_id', '=', picking.id)])
                            backorder_pick.action_cancel()
                            picking.message_post(body=_("Back order %s cancelled.") % (backorder_pick.name))
                line.sale_order.action_invoice_create()
                line.state = 'invoiced'

    @api.multi
    def validate_invoice(self):
        for line in self:
            if line.state == 'invoiced':
                line.sale_order.invoice_ids.signal_workflow('invoice_open')
                line.state = 'invoice_validated'

    @api.multi
    def send_invoice(self):
        mail_template = self.env.ref('account.email_template_edi_invoice', False)
        for line in self:
            if line.state == 'invoice_validated':
                mail_template.send_mail(line.sale_order.invoice_ids.id, False)
                line.state = 'sale_sent'<|endoftext|>


<commit_before>from django.db import models
from django.utils.timezone import now
from uuidfield import UUIDField

from .managers import EmailManager

class Domain(models.Model):
    uuid = UUIDField(auto=True, primary_key=True)
    name = models.CharField(max_length=200, unique=True)

    def __unicode__(self):
        return self.name

class Recipient(models.Model):
    uuid = UUIDField(auto=True, primary_key=True)
    email = models.EmailField(unique=True)
    domain = models.ForeignKey(Domain, related_name='users')

    class Meta:
        ordering = ['domain', 'email']

    def __unicode__(self):
        return self.email

    def save(self, *args, **kwargs):
        if not self.uuid:
            domain = '.'.join(self.email.split('@')[1].split('.')[-2:])
            self.domain, created = Domain.objects.get_or_create(name=domain)
        super(Recipient, self).save(*args, **kwargs)

class Email(models.Model):
    uuid = UUIDField(auto=True, primary_key=True)
    message_id = models.CharField(max_length=1000)
    sender = models.EmailField()
    recipient = models.ForeignKey(Recipient, related_name='emails')
    subject = models.CharField(max_length=1000)
    date = models.DateTimeField()
    header = models.TextField()
    body = models.TextField()

    objects = EmailManager()

    class Meta:
        ordering = ['-date']
        unique_together = ('message_id', 'recipient')

    def __unicode__(self):
        return self.message_id

    def save(self, *args, **kwargs):
        if self.date is None:
            self.date = now()
        super(Email, self).save(*args, **kwargs)
<commit_msg>Increased Domain.name max_length<commit_after>from django.db import models
from django.utils.timezone import now
from uuidfield import UUIDField

from .managers import EmailManager

class Domain(models.Model):
    uuid = UUIDField(auto=True, primary_key=True)
    name = models.CharField(max_length=255, unique=True)

    def __unicode__(self):
        return self.name

class Recipient(models.Model):
    uuid = UUIDField(auto=True, primary_key=True)
    email = models.EmailField(unique=True)
    domain = models.ForeignKey(Domain, related_name='users')

    class Meta:
        ordering = ['domain', 'email']

    def __unicode__(self):
        return self.email

    def save(self, *args, **kwargs):
        if not self.uuid:
            domain = '.'.join(self.email.split('@')[1].split('.')[-2:])
            self.domain, created = Domain.objects.get_or_create(name=domain)
        super(Recipient, self).save(*args, **kwargs)

class Email(models.Model):
    uuid = UUIDField(auto=True, primary_key=True)
    message_id = models.CharField(max_length=1000)
    sender = models.EmailField()
    recipient = models.ForeignKey(Recipient, related_name='emails')
    subject = models.CharField(max_length=1000)
    date = models.DateTimeField()
    header = models.TextField()
    body = models.TextField()

    objects = EmailManager()

    class Meta:
        ordering = ['-date']
        unique_together = ('message_id', 'recipient')

    def __unicode__(self):
        return self.message_id

    def save(self, *args, **kwargs):
        if self.date is None:
            self.date = now()
        super(Email, self).save(*args, **kwargs)
<|endoftext|>


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

Usage:
    gpxseg -c <source_folder> <target_folder>
    gpxseg -m <source_folder> <target_folder>
    gpxseg -c -s <source_folder> -t <target_folder>
    gpxseg -m -s <source_folder> -t <target_folder>

Options:
    -h --help       Show this screen.
    --version       Show version.
    -c              Copy mode.
    -m              Move mode.
    -s --source     Set source folder.
    -t --target     Set target folder.
"""
from __future__ import print_function
from docopt import docopt
args = docopt(__doc__)

from xml.dom import minidom
import datetime
import logging
import os
import shutil
import sys
import tzlocal
import pytz

from nominatim import NominatimReverse

logger = logging.getLogger()
watchpaths = []
watchpaths.append(args['<source_folder>'])
targetpath = args['<target_folder>']

if not os.path.isdir(args['<source_folder>']) or not os.path.isdir(args['<target_folder>']):
    print('One of paths is not a folder,\nplease specify folder paths')
    sys.exit(2)

def find_files_in_folder(folderpaths=watchpaths,
                         extentions=['gpx']):
    """
    Return list of paths to files with extentions from second argument which
    are stored in folders from first argument.
    Both arguments should be lists.
    """
    for x in folderpaths:
        x = os.path.expanduser(x)
        for root, dirs, files in os.walk(x):
            for file in files:
                for extention in extentions:
                    if extention in file[-len(extention):]:
                        """
                        file[-len(extention):] beacouse it shuld work only if
                        end of file name is matching, TODO: i can try using
                        endswith method of str
                        """
                        yield os.path.join(root, file)

class Coordinate():
    """docstring for Coordinate"""
    def __init__(self, lat, lon, dt):
        self.lat, self.lon = lat, lon
        self.dt = dt
        utc = pytz.utc
        self.dt = utc.localize(self.dt)
        localtimezone = tzlocal.get_localzone()
        self.dt = self.dt.astimezone(localtimezone)
        self.address = ''

    def __repr__(self):
        if self.address:
            return '''Coordinate instance:\nlat: %s\nlon: %s\ndt: %s
address:%s''' % (self.lat, self.lon, self.dt, self.address)
        else:
            return ''''Coordinate instance:\nlat: %s\nlon: %s
dt: %s''' % (self.lat, self.lon, self.dt)

    def fetchaddress(self):
        """docstring for fetchaddress"""

        nomrev = NominatimReverse()
        self.osm = nomrev.query(self.lat, self.lon)

        adr = self.osm['address']

        if 'road' not in adr:
            adr[u'road'] = u''
        if 'path' not in adr:
            adr[u'path'] = u''

        if 'house_number' not in adr:
            adr[u'house_number'] = u''

        if 'city_district' not in adr:
            adr[u'city_district'] = u''
        if 'suburb' not in adr:
            adr[u'suburb'] = u''

        if 'city' not in adr:
            adr[u'city'] = u''
        if 'town' not in adr:
            adr[u'town'] = u''
        if 'village' not in adr:
            adr[u'village'] = u''

        if adr['house_number'] and adr['road']:
            adr[u'road_house_number'] = adr['road'] + u' ' + adr['house_number'] + u', '
        elif adr['road']:
            adr[u'road_house_number'] = adr['road'] + u', '
        elif adr['path']:
            adr[u'road_house_number'] = adr['path'] + u', '
        else:
            adr[u'road_house_number'] = u''

        if adr['city_district'] and adr['suburb']:
            adr[u'district_suburb'] = adr['suburb'] + u', '
        elif adr['city_district']:
            adr[u'district_suburb'] = adr['city_district'] + u', '
        elif adr['suburb']:
            adr[u'district_suburb'] = adr['suburb'] + u', '
        else:
            adr[u'district_suburb'] = u''

        sn = u'{road_house_number}{district_suburb}{city}{town}{village}'.format(**adr)
        self.shortaddress = sn.strip()

class File():
    """docstring for File"""
    def __init__(self, filepath):
        self.filepath = filepath

class Gpx(File):
    """docstring for Gpx"""
    def load(self):
        """docstring for load"""
        self.DOMTree = minidom.parse(self.filepath)
        trkptlist = self.DOMTree.getElementsByTagName('trkpt')
        self.ITEMS = []
        for item in trkptlist:
            if sys.version_info.major == 3:
                time = str(item.getElementsByTagName('time')[0].firstChild.data.encode('utf-8'), encoding='utf-8')
            else:
                time = str(item.getElementsByTagName('time')[0].firstChild.data.encode('utf-8'))
            try:
                dt = datetime.datetime.strptime(time, '%Y-%m-%dT%H:%M:%S.%fZ')
            except:
                dt = datetime.datetime.strptime(time, '%Y-%m-%dT%H:%M:%SZ')
            coordinate = Coordinate(item.attributes['lat'].value,
                                    item.attributes['lon'].value,
                                    dt)
            self.ITEMS.append(coordinate)

    def namegen(self):
        """docstring for namegen"""
        def z(x):
            if type(x) == 'str':
                if int(x) < 10:
                    return '0' + x
                else:
                    return x
            else:
                if x < 10:
                    return '0' + str(x)
                else:
                    return str(x)
        first = self.ITEMS[0]
        first.fetchaddress()
        self.newname = '%s-%s-%s %s.%s %s' % (first.dt.year,
            z(first.dt.month), z(first.dt.day), z(first.dt.hour),
            z(first.dt.minute), first.shortaddress
        )
        self.newname = self.newname.replace('/', '.')

    def copyfile(self):
        """docstring for copyfile"""
        target = os.path.join(os.path.expanduser(targetpath), self.newname + '.gpx')
        if sys.version_info.major == 2:
            target = target.encode('utf-8', 'ignore')
        if self.newname:
            shutil.copyfile(self.filepath, target)
            print('%s\ncopied to\n%s' % (self.filepath, target))

    def movefile(self):
        """docstring for movefile"""
        target = os.path.join(os.path.expanduser(targetpath), self.newname + '.gpx')
        if sys.version_info.major == 2:
            target = target.encode('utf-8', 'ignore')
        if self.newname:
            shutil.move(self.filepath, target)
            print('%s\nmoved to\n%s' % (self.filepath, target))

def main():
    for f in find_files_in_folder():
        gpx = Gpx(f)
        gpx.load()
        gpx.namegen()
        if args['-c']:
            gpx.copyfile()
        if args['-m']:
            gpx.movefile()
        print('')

if __name__ == '__main__':
    main()
<commit_msg>Colors in output. Fixes #3<commit_after>#! /usr/bin/env python
"""gpxseg

Usage:
    gpxseg -c <source_folder> <target_folder>
    gpxseg -m <source_folder> <target_folder>
    gpxseg -c -s <source_folder> -t <target_folder>
    gpxseg -m -s <source_folder> -t <target_folder>

Options:
    -h --help       Show this screen.
    --version       Show version.
    -c              Copy mode.
    -m              Move mode.
    -s --source     Set source folder.
    -t --target     Set target folder.
"""
from __future__ import print_function
from docopt import docopt
args = docopt(__doc__)

from xml.dom import minidom
from colorama import Fore
import datetime
import logging
import os
import shutil
import sys
import tzlocal
import pytz

from nominatim import NominatimReverse

logger = logging.getLogger()
watchpaths = []
watchpaths.append(args['<source_folder>'])
targetpath = args['<target_folder>']

if not os.path.isdir(args['<source_folder>']) or not os.path.isdir(args['<target_folder>']):
    print('One of paths is not a folder,\nplease specify folder paths')
    sys.exit(2)

def find_files_in_folder(folderpaths=watchpaths,
                         extentions=['gpx']):
    """
    Return list of paths to files with extentions from second argument which
    are stored in folders from first argument.
    Both arguments should be lists.
    """
    for x in folderpaths:
        x = os.path.expanduser(x)
        for root, dirs, files in os.walk(x):
            for file in files:
                for extention in extentions:
                    if extention in file[-len(extention):]:
                        """
                        file[-len(extention):] beacouse it shuld work only if
                        end of file name is matching, TODO: i can try using
                        endswith method of str
                        """
                        yield os.path.join(root, file)

class Coordinate():
    """docstring for Coordinate"""
    def __init__(self, lat, lon, dt):
        self.lat, self.lon = lat, lon
        self.dt = dt
        utc = pytz.utc
        self.dt = utc.localize(self.dt)
        localtimezone = tzlocal.get_localzone()
        self.dt = self.dt.astimezone(localtimezone)
        self.address = ''

    def __repr__(self):
        if self.address:
            return '''Coordinate instance:\nlat: %s\nlon: %s\ndt: %s
address:%s''' % (self.lat, self.lon, self.dt, self.address)
        else:
            return ''''Coordinate instance:\nlat: %s\nlon: %s
dt: %s''' % (self.lat, self.lon, self.dt)

    def fetchaddress(self):
        """docstring for fetchaddress"""

        nomrev = NominatimReverse()
        self.osm = nomrev.query(self.lat, self.lon)

        adr = self.osm['address']

        if 'road' not in adr:
            adr[u'road'] = u''
        if 'path' not in adr:
            adr[u'path'] = u''

        if 'house_number' not in adr:
            adr[u'house_number'] = u''

        if 'city_district' not in adr:
            adr[u'city_district'] = u''
        if 'suburb' not in adr:
            adr[u'suburb'] = u''

        if 'city' not in adr:
            adr[u'city'] = u''
        if 'town' not in adr:
            adr[u'town'] = u''
        if 'village' not in adr:
            adr[u'village'] = u''

        if adr['house_number'] and adr['road']:
            adr[u'road_house_number'] = adr['road'] + u' ' + adr['house_number'] + u', '
        elif adr['road']:
            adr[u'road_house_number'] = adr['road'] + u', '
        elif adr['path']:
            adr[u'road_house_number'] = adr['path'] + u', '
        else:
            adr[u'road_house_number'] = u''

        if adr['city_district'] and adr['suburb']:
            adr[u'district_suburb'] = adr['suburb'] + u', '
        elif adr['city_district']:
            adr[u'district_suburb'] = adr['city_district'] + u', '
        elif adr['suburb']:
            adr[u'district_suburb'] = adr['suburb'] + u', '
        else:
            adr[u'district_suburb'] = u''

        sn = u'{road_house_number}{district_suburb}{city}{town}{village}'.format(**adr)
        self.shortaddress = sn.strip()

class File():
    """docstring for File"""
    def __init__(self, filepath):
        self.filepath = filepath

class Gpx(File):
    """docstring for Gpx"""
    def load(self):
        """docstring for load"""
        self.DOMTree = minidom.parse(self.filepath)
        trkptlist = self.DOMTree.getElementsByTagName('trkpt')
        self.ITEMS = []
        for item in trkptlist:
            if sys.version_info.major == 3:
                time = str(item.getElementsByTagName('time')[0].firstChild.data.encode('utf-8'), encoding='utf-8')
            else:
                time = str(item.getElementsByTagName('time')[0].firstChild.data.encode('utf-8'))
            try:
                dt = datetime.datetime.strptime(time, '%Y-%m-%dT%H:%M:%S.%fZ')
            except:
                dt = datetime.datetime.strptime(time, '%Y-%m-%dT%H:%M:%SZ')
            coordinate = Coordinate(item.attributes['lat'].value,
                                    item.attributes['lon'].value,
                                    dt)
            self.ITEMS.append(coordinate)

    def namegen(self):
        """docstring for namegen"""
        def z(x):
            if type(x) == 'str':
                if int(x) < 10:
                    return '0' + x
                else:
                    return x
            else:
                if x < 10:
                    return '0' + str(x)
                else:
                    return str(x)
        first = self.ITEMS[0]
        first.fetchaddress()
        self.newname = '%s-%s-%s %s.%s %s' % (first.dt.year,
            z(first.dt.month), z(first.dt.day), z(first.dt.hour),
            z(first.dt.minute), first.shortaddress
        )
        self.newname = self.newname.replace('/', '.')

    def copyfile(self):
        """docstring for copyfile"""
        target = os.path.join(os.path.expanduser(targetpath), self.newname + '.gpx')
        if sys.version_info.major == 2:
            target = target.encode('utf-8', 'ignore')
        if self.newname:
            shutil.copyfile(self.filepath, target)
            print('%s\ncopied to\n%s' % (self.filepath, target))

    def movefile(self):
        """docstring for movefile"""
        target = os.path.join(os.path.expanduser(targetpath), self.newname + '.gpx')
        if sys.version_info.major == 2:
            target = target.encode('utf-8', 'ignore')
        if self.newname:
            shutil.move(self.filepath, target)
            print('%s\nmoved to\n%s' % (self.filepath, target))

def main():
    colors = [Fore.BLUE, Fore.GREEN, Fore.RED, Fore.YELLOW]
    num = 0
    for f in find_files_in_folder():
        gpx = Gpx(f)
        gpx.load()
        gpx.namegen()
        print(colors[num])
        if args['-c']:
            gpx.copyfile()
        if args['-m']:
            gpx.movefile()
        if num >= len(colors)-1:
            num = 0
        else:
            num += 1

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


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

from oslo_log import log as logging
from tempest.common import waiters
from tempest import config
from tempest import test

from ironic_tempest_plugin.tests.scenario import baremetal_manager

CONF = config.CONF

LOG = logging.getLogger(__name__)

class BaremetalBasicOps(baremetal_manager.BaremetalScenarioTest):
    """This smoke test tests the pxe_ssh Ironic driver.

    It follows this basic set of operations:
        * Creates a keypair
        * Boots an instance using the keypair
        * Monitors the associated Ironic node for power and
          expected state transitions
        * Validates Ironic node's port data has been properly updated
        * Verifies SSH connectivity using created keypair via fixed IP
        * Associates a floating ip
        * Verifies SSH connectivity using created keypair via floating IP
        * Verifies instance rebuild with ephemeral partition preservation
        * Deletes instance
        * Monitors the associated Ironic node for power and
          expected state transitions
    """
    def rebuild_instance(self, preserve_ephemeral=False):
        self.rebuild_server(server_id=self.instance['id'],
                            preserve_ephemeral=preserve_ephemeral,
                            wait=False)

        node = self.get_node(instance_id=self.instance['id'])

        # We should remain on the same node
        self.assertEqual(self.node['uuid'], node['uuid'])
        self.node = node

        waiters.wait_for_server_status(
            self.servers_client,
            server_id=self.instance['id'],
            status='REBUILD',
            ready_wait=False)
        waiters.wait_for_server_status(
            self.servers_client,
            server_id=self.instance['id'],
            status='ACTIVE')

    def verify_partition(self, client, label, mount, gib_size):
        """Verify a labeled partition's mount point and size."""
        LOG.info("Looking for partition %s mounted on %s" % (label, mount))

        # Validate we have a device with the given partition label
        cmd = "/sbin/blkid | grep '%s' | cut -d':' -f1" % label
        device = client.exec_command(cmd).rstrip('\n')
        LOG.debug("Partition device is %s" % device)
        self.assertNotEqual('', device)

        # Validate the mount point for the device
        cmd = "mount | grep '%s' | cut -d' ' -f3" % device
        actual_mount = client.exec_command(cmd).rstrip('\n')
        LOG.debug("Partition mount point is %s" % actual_mount)
        self.assertEqual(actual_mount, mount)

        # Validate the partition size matches what we expect
        numbers = '0123456789'
        devnum = device.replace('/dev/', '')
        cmd = "cat /sys/block/%s/%s/size" % (devnum.rstrip(numbers), devnum)
        num_bytes = client.exec_command(cmd).rstrip('\n')
        num_bytes = int(num_bytes) * 512
        actual_gib_size = num_bytes / (1024 * 1024 * 1024)
        LOG.debug("Partition size is %d GiB" % actual_gib_size)
        self.assertEqual(actual_gib_size, gib_size)

    def get_flavor_ephemeral_size(self):
        """Returns size of the ephemeral partition in GiB."""
        f_id = self.instance['flavor']['id']
        flavor = self.flavors_client.show_flavor(f_id)['flavor']
        ephemeral = flavor.get('OS-FLV-EXT-DATA:ephemeral')
        if not ephemeral or ephemeral == 'N/A':
            return None
        return int(ephemeral)

    def validate_ports(self):
        for port in self.get_ports(self.node['uuid']):
            n_port_id = port['extra']['vif_port_id']
            body = self.ports_client.show_port(n_port_id)
            n_port = body['port']
            self.assertEqual(n_port['device_id'], self.instance['id'])
            self.assertEqual(n_port['mac_address'], port['address'])

    @test.idempotent_id('549173a5-38ec-42bb-b0e2-c8b9f4a08943')
    @test.services('baremetal', 'compute', 'image', 'network')
    def test_baremetal_server_ops(self):
        self.add_keypair()
        self.boot_instance()
        self.validate_ports()
        self.verify_connectivity()
        if CONF.validation.connect_method == 'floating':
            floating_ip = self.create_floating_ip(self.instance)['ip']
            self.verify_connectivity(ip=floating_ip)

        vm_client = self.get_remote_client(self.instance)

        # We expect the ephemeral partition to be mounted on /mnt and to have
        # the same size as our flavor definition.
        eph_size = self.get_flavor_ephemeral_size()
        if eph_size:
            self.verify_partition(vm_client, 'ephemeral0', '/mnt', eph_size)
            # Create the test file
            self.create_timestamp(
                floating_ip, private_key=self.keypair['private_key'])

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

from oslo_log import log as logging
from tempest.common import waiters
from tempest import config
from tempest import test

from ironic_tempest_plugin.tests.scenario import baremetal_manager

CONF = config.CONF

LOG = logging.getLogger(__name__)

class BaremetalBasicOps(baremetal_manager.BaremetalScenarioTest):
    """This smoke test tests the pxe_ssh Ironic driver.

    It follows this basic set of operations:
        * Creates a keypair
        * Boots an instance using the keypair
        * Monitors the associated Ironic node for power and
          expected state transitions
        * Validates Ironic node's port data has been properly updated
        * Verifies SSH connectivity using created keypair via fixed IP
        * Associates a floating ip
        * Verifies SSH connectivity using created keypair via floating IP
        * Verifies instance rebuild with ephemeral partition preservation
        * Deletes instance
        * Monitors the associated Ironic node for power and
          expected state transitions
    """
    def rebuild_instance(self, preserve_ephemeral=False):
        self.rebuild_server(server_id=self.instance['id'],
                            preserve_ephemeral=preserve_ephemeral,
                            wait=False)

        node = self.get_node(instance_id=self.instance['id'])

        # We should remain on the same node
        self.assertEqual(self.node['uuid'], node['uuid'])
        self.node = node

        waiters.wait_for_server_status(
            self.servers_client,
            server_id=self.instance['id'],
            status='REBUILD',
            ready_wait=False)
        waiters.wait_for_server_status(
            self.servers_client,
            server_id=self.instance['id'],
            status='ACTIVE')

    def verify_partition(self, client, label, mount, gib_size):
        """Verify a labeled partition's mount point and size."""
        LOG.info("Looking for partition %s mounted on %s" % (label, mount))

        # Validate we have a device with the given partition label
        cmd = "/sbin/blkid | grep '%s' | cut -d':' -f1" % label
        device = client.exec_command(cmd).rstrip('\n')
        LOG.debug("Partition device is %s" % device)
        self.assertNotEqual('', device)

        # Validate the mount point for the device
        cmd = "mount | grep '%s' | cut -d' ' -f3" % device
        actual_mount = client.exec_command(cmd).rstrip('\n')
        LOG.debug("Partition mount point is %s" % actual_mount)
        self.assertEqual(actual_mount, mount)

        # Validate the partition size matches what we expect
        numbers = '0123456789'
        devnum = device.replace('/dev/', '')
        cmd = "cat /sys/block/%s/%s/size" % (devnum.rstrip(numbers), devnum)
        num_bytes = client.exec_command(cmd).rstrip('\n')
        num_bytes = int(num_bytes) * 512
        actual_gib_size = num_bytes / (1024 * 1024 * 1024)
        LOG.debug("Partition size is %d GiB" % actual_gib_size)
        self.assertEqual(actual_gib_size, gib_size)

    def get_flavor_ephemeral_size(self):
        """Returns size of the ephemeral partition in GiB."""
        f_id = self.instance['flavor']['id']
        flavor = self.flavors_client.show_flavor(f_id)['flavor']
        ephemeral = flavor.get('OS-FLV-EXT-DATA:ephemeral')
        if not ephemeral or ephemeral == 'N/A':
            return None
        return int(ephemeral)

    def validate_ports(self):
        for port in self.get_ports(self.node['uuid']):
            n_port_id = port['extra']['vif_port_id']
            body = self.ports_client.show_port(n_port_id)
            n_port = body['port']
            self.assertEqual(n_port['device_id'], self.instance['id'])
            self.assertEqual(n_port['mac_address'], port['address'])

    @test.idempotent_id('549173a5-38ec-42bb-b0e2-c8b9f4a08943')
    @test.services('baremetal', 'compute', 'image', 'network')
    def test_baremetal_server_ops(self):
        self.add_keypair()
        self.boot_instance()
        self.validate_ports()
        ip_address = self.get_server_ip(self.instance)
        self.get_remote_client(ip_address).validate_authentication()
        vm_client = self.get_remote_client(ip_address)

        # We expect the ephemeral partition to be mounted on /mnt and to have
        # the same size as our flavor definition.
        eph_size = self.get_flavor_ephemeral_size()
        if eph_size:
            self.verify_partition(vm_client, 'ephemeral0', '/mnt', eph_size)
            # Create the test file
            self.create_timestamp(
                ip_address, private_key=self.keypair['private_key'])

        self.terminate_instance()
<|endoftext|>


<commit_before>from enum import Enum

from OpenGL.GLUT import glutMainLoop

from src import MFM, View

class Texture(Enum):
    light = 0
    normal = 1

class Model:
    def __init__(self):
        self.__light = True
        self.__face = None
        self.__view = View((500, 500))

        self.__texture = Texture.light

        self.__rotations = {
            'x': 0.,
            'y': 0.,
            'z': 0.
        }

        self.calculate()

    def start(self):
        glutMainLoop()

    def redraw(self):
        self.__view.redraw()

    def calculate(self, new_model=True):
        if new_model:
            self.__face = MFM.get_face()

        vertices = self.__face.get_vertices_c()
        if self.__texture == Texture.light:
            colors = self.__face.get_light_map_c()
        else:
            colors = self.__face.get_normal_map_c()

        self.__view.update(vertices, colors)

    def rotate(self, axis, value):
        self.__rotations[axis] = value
        rotation = (self.__rotations['x'], self.__rotations['y'],
                    self.__rotations['z'])
        self.__view.update(rotation=rotation)

    def toggle_texture(self):
        self.__texture = Texture.normal if self.__texture == Texture.light \
                    else Texture.light

    def close(self):
        self.__view.close()
<commit_msg>Added ability to change light parameter for Model<commit_after>from enum import Enum

from OpenGL.GLUT import glutMainLoop

from src import MFM, View

class Texture(Enum):
    light = 0
    normal = 1

class Model:
    def __init__(self):
        self.__light = True
        self.__face = None
        self.__view = View((500, 500))

        self.__texture = Texture.light

        self.__rotations = {
            'x': 0.,
            'y': 0.,
            'z': 0.
        }
        self.__light = {
            'x': 0.,
            'y': 0.,
            'z': 0.
        }

        self.calculate()

    def start(self):
        glutMainLoop()

    def redraw(self):
        self.__view.redraw()

    def calculate(self, new_model=True):
        if new_model:
            self.__face = MFM.get_face()

        vertices = self.__face.get_vertices_c()
        if self.__texture == Texture.light:
            colors = self.__face.get_light_map_c()
        else:
            colors = self.__face.get_normal_map_c()

        self.__view.update(vertices, colors)

    def rotate(self, axis, value):
        self.__rotations[axis] = value
        rotation = (self.__rotations['x'], self.__rotations['y'],
                    self.__rotations['z'])
        self.__view.update(rotation=rotation)

    def change_light(self, direction=None, intensity=None):
        if direction is not None:
            x, y, z = self.__face.get_directed_light()
            self.__face.set_light(directed_light=(x + direction['x'],
                                  y + direction['y'], z + direction['z']))
        if intensity is not None:
            constant_light = self.__face.get_constant_light()
            constant_light += intensity
            self.__face.set_light(constant_light=constant_light)
        self.calculate(False)

    def toggle_texture(self):
        self.__texture = Texture.normal if self.__texture == Texture.light \
                    else Texture.light

    def close(self):
        self.__view.close()
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
refrigeration loads
"""
from __future__ import division
import numpy as np
import pandas as pd
from cea.technologies import heatpumps
from cea.constants import HOURS_IN_YEAR
from cea.demand.constants import T_C_REF_SUP_0, T_C_REF_RE_0

__author__ = "Jimeno A. Fonseca"
__copyright__ = "Copyright 2016, Architecture and Building Systems - ETH Zurich"
__credits__ = ["Jimeno A. Fonseca"]
__license__ = "MIT"
__version__ = "0.1"
__maintainer__ = "Daren Thomas"
__email__ = "cea@arch.ethz.ch"
__status__ = "Production"

def has_refrigeration_load(bpr):
    """
    Checks if building has a hot water system

    :param bpr: BuildingPropertiesRow
    :type bpr: cea.demand.building_properties.BuildingPropertiesRow
    :return: True or False
    :rtype: bool
        """

    if bpr.internal_loads['Qcre_Wm2'] > 0:
        return True
    else:
        return False

def calc_Qcre_sys(bpr, tsd, schedules):
    # calculate refrigeration loads
    tsd['Qcre'] = schedules['Qcre'] * bpr.internal_loads['Qcre_Wm2'] * -1.0  # cooling loads are negative
    # calculate distribution losses for refrigeration loads analogously to space cooling distribution losses
    Y = bpr.building_systems['Y'][0]
    Lv = bpr.building_systems['Lv']
    Qcre_d_ls = ((T_C_REF_SUP_0 + T_C_REF_RE_0) / 2 - tsd['T_ext']) * (tsd['Qcre'] / np.nanmin(tsd['Qcre'])) * (Lv * Y)
    # calculate system loads for data center
    tsd['Qcre_sys'] = tsd['Qcre'] + Qcre_d_ls

    # writing values to tsd, replacing function and np.vectorize call with simple for loop
    for h in range(HOURS_IN_YEAR):
        if tsd['Qcre_sys'][h] > 0:
            tsd['mcpcre_sys'][h] = tsd['Qcre_sys'][h] / (T_C_REF_RE_0 - T_C_REF_SUP_0)
            tsd['Tcre_sys_re'][h] = T_C_REF_RE_0
            tsd['Tcre_sys_sup'][h] = T_C_REF_SUP_0

    return tsd

def calc_Qref(locator, bpr, tsd):
    """
    it calculates final loads
    """
    # GET SYSTEMS EFFICIENCIES
    data_systems = pd.read_excel(locator.get_life_cycle_inventory_supply_systems(), "COOLING").set_index('code')
    type_system = bpr.supply['type_cs']
    energy_source = data_systems.loc[type_system, 'source_cs']

    if energy_source == "GRID":
        if bpr.supply['type_cs'] in {'T2', 'T3'}:
            if bpr.supply['type_cs'] == 'T2':
                t_source = (tsd['T_ext'] + 273)
            if bpr.supply['type_cs'] == 'T3':
                t_source = (tsd['T_ext_wetbulb'] + 273)

            # heat pump energy
            tsd['E_cre'] = np.vectorize(heatpumps.HP_air_air)(tsd['mcpcre_sys'], (tsd['Tcre_sys_sup'] + 273),
                                                                (tsd['Tcre_sys_re'] + 273), t_source)
            # final to district is zero
            tsd['DC_cre'] = np.zeros(HOURS_IN_YEAR)
    elif energy_source == "DC":
        tsd['DC_cre'] = tsd['Qcre_sys']
        tsd['E_cre'] = np.zeros(HOURS_IN_YEAR)
    else:
        tsd['E_cre'] = np.zeros(HOURS_IN_YEAR)

    return tsd

<commit_msg>Update refrigeration_loads.py<commit_after># -*- coding: utf-8 -*-
"""
refrigeration loads
"""
from __future__ import division
import numpy as np
import pandas as pd
from cea.technologies import heatpumps
from cea.constants import HOURS_IN_YEAR
from cea.demand.constants import T_C_REF_SUP_0, T_C_REF_RE_0

__author__ = "Jimeno A. Fonseca"
__copyright__ = "Copyright 2016, Architecture and Building Systems - ETH Zurich"
__credits__ = ["Jimeno A. Fonseca", "Martin Mosteiro", "Gabriel Happle"]
__license__ = "MIT"
__version__ = "0.1"
__maintainer__ = "Daren Thomas"
__email__ = "cea@arch.ethz.ch"
__status__ = "Production"

def has_refrigeration_load(bpr):
    """
    Checks if building has a hot water system

    :param bpr: BuildingPropertiesRow
    :type bpr: cea.demand.building_properties.BuildingPropertiesRow
    :return: True or False
    :rtype: bool
        """

    if bpr.internal_loads['Qcre_Wm2'] > 0:
        return True
    else:
        return False

def calc_Qcre_sys(bpr, tsd, schedules):
    # calculate refrigeration loads
    tsd['Qcre'] = schedules['Qcre'] * bpr.internal_loads['Qcre_Wm2'] * -1.0  # cooling loads are negative
    # calculate distribution losses for refrigeration loads analogously to space cooling distribution losses
    Y = bpr.building_systems['Y'][0]
    Lv = bpr.building_systems['Lv']
    Qcre_d_ls = ((T_C_REF_SUP_0 + T_C_REF_RE_0) / 2.0 - tsd['T_ext']) * (tsd['Qcre'] / np.nanmin(tsd['Qcre'])) * (Lv * Y)
    # calculate system loads for data center
    tsd['Qcre_sys'] = tsd['Qcre'] + Qcre_d_ls

    # writing values to tsd, replacing function and np.vectorize call with simple for loop
    tsd['mcpcre_sys'], tsd['Tcre_sys_re'], tsd['Tcre_sys_sup'] =\
        np.vectorize(calc_refrigeration_temperature_and_massflow)(tsd['Qcre_sys'])

    return tsd

def calc_refrigeration_temperature_and_massflow(Qcre_sys):
    """
    Calculate refrigeration supply and return temperatures and massflows based on the refrigeration load
    This function is intended to be used in np.vectorize form
    :param Qcre_sys: refrigeration load including losses
    :return: refrigeration massflow, refrigeration supply temperature, refrigeration return temperature
    """

    if Qcre_sys > 0.0:
        mcpcre_sys = Qcre_sys / (T_C_REF_RE_0 - T_C_REF_SUP_0)
        Tcre_sys_re = T_C_REF_RE_0
        Tcre_sys_sup = T_C_REF_SUP_0
    else:
        mcpcre_sys = np.nan
        Tcre_sys_re = np.nan
        Tcre_sys_sup = np.nan

    return mcpcre_sys, Tcre_sys_re, Tcre_sys_sup

def calc_Qref(locator, bpr, tsd):
    """
    it calculates final loads
    """
    # GET SYSTEMS EFFICIENCIES
    data_systems = pd.read_excel(locator.get_life_cycle_inventory_supply_systems(), "COOLING").set_index('code')
    type_system = bpr.supply['type_cs']
    energy_source = data_systems.loc[type_system, 'source_cs']

    if energy_source == "GRID":
        if bpr.supply['type_cs'] in {'T2', 'T3'}:
            if bpr.supply['type_cs'] == 'T2':
                t_source = (tsd['T_ext'] + 273)
            if bpr.supply['type_cs'] == 'T3':
                t_source = (tsd['T_ext_wetbulb'] + 273)

            # heat pump energy
            tsd['E_cre'] = np.vectorize(heatpumps.HP_air_air)(tsd['mcpcre_sys'], (tsd['Tcre_sys_sup'] + 273),
                                                                (tsd['Tcre_sys_re'] + 273), t_source)
            # final to district is zero
            tsd['DC_cre'] = np.zeros(HOURS_IN_YEAR)
    elif energy_source == "DC":
        tsd['DC_cre'] = tsd['Qcre_sys']
        tsd['E_cre'] = np.zeros(HOURS_IN_YEAR)
    else:
        tsd['E_cre'] = np.zeros(HOURS_IN_YEAR)

    return tsd

<|endoftext|>


<commit_before>VERSION = (0,6,3,2)<commit_msg>Version bump<commit_after>VERSION = (0,6,3,3)<|endoftext|>