<commit_before># Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
# Copyright (C) 2011 Isaku Yamahata <yamahata at valinux co jp>
#
# 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.

import inspect
import logging
import os
import sys
import re

LOG = logging.getLogger('ryu.utils')

def import_module(modname):
    try:
        __import__(modname)
    except:
        sys.path.append(os.path.dirname(os.path.abspath(modname)))
        name = os.path.basename(modname)
        if name.endswith('.py'):
            name = name[:-3]
        __import__(name)
        return sys.modules[name]
    return sys.modules[modname]

RYU_DEFAULT_FLAG_FILE = ('ryu.conf', 'etc/ryu/ryu.conf' '/etc/ryu/ryu.conf')

def find_flagfile(default_path=RYU_DEFAULT_FLAG_FILE):
    if '--flagfile' in sys.argv:
        return

    script_dir = os.path.dirname(inspect.stack()[-1][1])

    for filename in default_path:
        if not os.path.isabs(filename):
            if os.path.exists(filename):
                # try relative to current path
                filename = os.path.abspath(filename)
            elif os.path.exists(os.path.join(script_dir, filename)):
                # try relative to script dir
                filename = os.path.join(script_dir, filename)

        if not os.path.exists(filename):
            continue

        flagfile = '--flagfile=%s' % filename
        sys.argv.insert(1, flagfile)
        LOG.debug('flagfile = %s', filename)
        return

def round_up(x, y):
    return ((x + y - 1) / y) * y

def hex_array(data):
    return ' '.join(hex(ord(chr)) for chr in data)

# the following functions are taken from OpenStack
#
# Get requirements from the first file that exists
def get_reqs_from_files(requirements_files):
    for requirements_file in requirements_files:
        if os.path.exists(requirements_file):
            with open(requirements_file, 'r') as fil:
                return fil.read().split('\n')
    return []

def parse_requirements(requirements_files=['requirements.txt',
                                           'tools/pip-requires']):
    requirements = []
    for line in get_reqs_from_files(requirements_files):
        # For the requirements list, we need to inject only the portion
        # after egg= so that distutils knows the package it's looking for
        # such as:
        # -e git://github.com/openstack/nova/master#egg=nova
        if re.match(r'\s*-e\s+', line):
            requirements.append(re.sub(r'\s*-e\s+.*#egg=(.*)$', r'\1',
                                line))
        # such as:
        # http://github.com/openstack/nova/zipball/master#egg=nova
        elif re.match(r'\s*https?:', line):
            requirements.append(re.sub(r'\s*https?:.*#egg=(.*)$', r'\1',
                                line))
        # -f lines are for index locations, and don't get used here
        elif re.match(r'\s*-f\s+', line):
            pass
        # argparse is part of the standard library starting with 2.7
        # adding it to the requirements list screws distro installs
        elif line == 'argparse' and sys.version_info >= (2, 7):
            pass
        else:
            requirements.append(line)

    return requirements
<commit_msg>fix lack of comma in flagfile list<commit_after># Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
# Copyright (C) 2011 Isaku Yamahata <yamahata at valinux co jp>
#
# 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.

import inspect
import logging
import os
import sys
import re

LOG = logging.getLogger('ryu.utils')

def import_module(modname):
    try:
        __import__(modname)
    except:
        sys.path.append(os.path.dirname(os.path.abspath(modname)))
        name = os.path.basename(modname)
        if name.endswith('.py'):
            name = name[:-3]
        __import__(name)
        return sys.modules[name]
    return sys.modules[modname]

RYU_DEFAULT_FLAG_FILE = ('ryu.conf', 'etc/ryu/ryu.conf', '/etc/ryu/ryu.conf')

def find_flagfile(default_path=RYU_DEFAULT_FLAG_FILE):
    if '--flagfile' in sys.argv:
        return

    script_dir = os.path.dirname(inspect.stack()[-1][1])

    for filename in default_path:
        if not os.path.isabs(filename):
            if os.path.exists(filename):
                # try relative to current path
                filename = os.path.abspath(filename)
            elif os.path.exists(os.path.join(script_dir, filename)):
                # try relative to script dir
                filename = os.path.join(script_dir, filename)

        if not os.path.exists(filename):
            continue

        flagfile = '--flagfile=%s' % filename
        sys.argv.insert(1, flagfile)
        LOG.debug('flagfile = %s', filename)
        return

def round_up(x, y):
    return ((x + y - 1) / y) * y

def hex_array(data):
    return ' '.join(hex(ord(chr)) for chr in data)

# the following functions are taken from OpenStack
#
# Get requirements from the first file that exists
def get_reqs_from_files(requirements_files):
    for requirements_file in requirements_files:
        if os.path.exists(requirements_file):
            with open(requirements_file, 'r') as fil:
                return fil.read().split('\n')
    return []

def parse_requirements(requirements_files=['requirements.txt',
                                           'tools/pip-requires']):
    requirements = []
    for line in get_reqs_from_files(requirements_files):
        # For the requirements list, we need to inject only the portion
        # after egg= so that distutils knows the package it's looking for
        # such as:
        # -e git://github.com/openstack/nova/master#egg=nova
        if re.match(r'\s*-e\s+', line):
            requirements.append(re.sub(r'\s*-e\s+.*#egg=(.*)$', r'\1',
                                line))
        # such as:
        # http://github.com/openstack/nova/zipball/master#egg=nova
        elif re.match(r'\s*https?:', line):
            requirements.append(re.sub(r'\s*https?:.*#egg=(.*)$', r'\1',
                                line))
        # -f lines are for index locations, and don't get used here
        elif re.match(r'\s*-f\s+', line):
            pass
        # argparse is part of the standard library starting with 2.7
        # adding it to the requirements list screws distro installs
        elif line == 'argparse' and sys.version_info >= (2, 7):
            pass
        else:
            requirements.append(line)

    return requirements
<|endoftext|>


<commit_before>from .utils import config, checks, formats
import discord
from discord.ext import commands
import discord.utils
import random, json, asyncio
from urllib.parse import unquote

class Radio:
    """The radio-bot related commands."""

    def __init__(self, bot):
        self.bot = bot
        if not discord.opus.is_loaded():
            discord.opus.load_opus('/usr/local/lib/libopus.so') #FreeBSD path

        self.player = None
        self.stopped = True
        self.break_loop = asyncio.Event()
        #self.break_loop.clear()
        self.q = asyncio.Queue()
        self.play_next_song = asyncio.Event()
        self.current_song = None
        self.songs_dir = 'radio/'
        self.songs = []
        self.playlists = {}
        self.update_song_list()

    @property
    def is_playing(self):
        return self.player is not None and self.player.is_playing() and not self.stopped

    def toggle_next_song(self):
        if not self.stopped:
            self.bot.loop.call_soon_threadsafe(self.play_next_song.set)

    def update_song_list(self):
        self.songs = self.bot.yadisk.list_files(self.songs_dir)
        self.update_playlists()

    def update_playlists(self):
        pl_files = self.bot.yadisk.list_files(self.songs_dir + 'playlists/')
        for pl in pl_files:
            pl_url = self.bot.yadisk.direct_link(self.songs_dir + 'playlists/' + pl)
            pl_data = self.bot.yadisk._get(pl_url).json()['songs']
            self.playlists[pl] = []
            for song in pl_data:
                if song in self.songs:
                    self.playlists[pl].append(song)

    @commands.command(pass_context=True)
    async def join(self, ctx, *, channel_name : str):
        """Зайти на указанный голосовой канал."""
        if self.bot.is_voice_connected():
            await ctx.invoke(self.leave)

        check = lambda c: c.name == channel_name and c.type == discord.ChannelType.voice
        channel = discord.utils.find(check, ctx.message.server.channels)
        if channel is None:
            await self.bot.say('Нет такого голосового канала.')
        await self.bot.join_voice_channel(channel)

    @commands.command(pass_context=True)
    async def leave(self, ctx):
        """Покинуть текущий голосовой канал."""
        await ctx.invoke(self.stop)
        await self.bot.voice.disconnect()

    @commands.command()
    async def pause(self):
        """Приостановить воспроизведение."""
        if self.player is not None:
            self.player.pause()

    @commands.command()
    async def resume(self):
        """Продолжить воспроизведение."""
        if self.player is not None and not self.is_playing:
            self.player.resume()

    @commands.command()
    async def skip(self):
        """Перейти к следующей песне в очереди."""
        if self.player is not None and self.is_playing:
            self.player.stop()
            self.toggle_next_song()

    @commands.command()
    async def stop(self):
        """Остановить воспроизведение."""
        if self.is_playing:
            self.break_loop.set()
            self.play_next_song.set()
            self.stopped = True
            self.player.stop()

    @commands.command(pass_context=True)
    async def play(self, ctx):
        """Начать воспроизведение песен из очереди."""
        if self.player is not None and not self.stopped:
            if not self.is_playing:
                await ctx.invoke(self.resume)
                return
            else:
                await self.bot.say('Уже играю песенку.')
                return

        while True:
            if not self.bot.is_voice_connected():
                author_channel = ctx.message.author.voice_channel
                if author_channel is not None:
                    print('Joining {}.'.format(author_channel.name))
                    await ctx.invoke(self.join, channel_name=author_channel.name)
                else:
                    await self.bot.say('Не выбран голосовой канал.')
                    return

            if self.q.empty():
                await self.q.put(random.choice(self.songs))
            self.play_next_song.clear()
            self.current = await self.q.get()
            self.player = self.bot.voice.create_ffmpeg_player(
                self.bot.yadisk.direct_link(self.songs_dir + self.current),
                after=self.toggle_next_song)
                #options="-loglevel debug -report",
                #headers = dict(self.bot.pycopy.session.headers)
            self.stopped = False
            self.player.start()
            song_name = unquote(self.current.split('/')[-1])
            await self.bot.change_status(discord.Game(name=song_name))

            await self.play_next_song.wait()
            if self.break_loop.is_set():
                self.break_loop.clear()
                return
        await self.bot.say('Leaving play loop')

    @commands.command(aliases=['c'])
    async def current(self):
        """Что там играет?"""
        if self.is_playing:
            song_name = unquote(self.current.split('/')[-1])
            await self.bot.say(song_name)

    @commands.command()
    async def update(self):
        """Обновить список песен."""
        self.update_song_list()
        await self.bot.say("Найдено {} песенок".format(len(self.songs)))

    @commands.command()
    async def list(self):
        """Вывести список всех доступных песен."""
        song_list = ""
        id = 1
        for song in self.songs:
            song_list += "{}. {}\n".format(id, song)
            id += 1
            if len(song_list) > 1800:
                await self.bot.say(song_list)
                song_list = ''
        await self.bot.say(song_list)

    @commands.command(aliases=['ss'])
    async def searchsong(self, search_word : str):
        """Искать песню по названию."""
        search_result = ""
        id = 1
        found = False
        for song in self.songs:
            if search_word.lower() in song.lower():
                found = True
                search_result += "{}. {}\n".format(id, song)
                if len(search_result) > 1800:
                    await self.bot.say(search_result)
                    search_result = ''
            id += 1
        if not found:
            search_result = "Нет такой песни."
        await self.bot.say(search_result)

    @commands.command()
    async def add(self, song_num : int):
        """Добавить в конец очереди песню с данным номером."""
        await self.q.put(self.songs[song_num-1])
        await self.bot.say("{} будет следующей песенкой".format(self.songs[song_num-1]))

    @commands.group(pass_context=True, aliases=['pl'])
    async def playlist(self):
        return

    @playlist.command()
    async def add(self, playlist : str, song : str):
        if not playlist in self.playlists:
            await ctx.invoke(self.new, playlist=playlist)
        self.playlists[playlist].append(song)
        pl_json = {'name': playlist, 'songs': self.playlists[playlist]}
        self.bot.yadisk.upload(self.songs_dir + 'playlists' + playlist, json.dumps(pl_json))

def setup(bot):
    bot.add_cog(Radio(bot))
<commit_msg>Update radio.py<commit_after>from .utils import config, checks, formats
import discord
from discord.ext import commands
import discord.utils
import random, json, asyncio
from urllib.parse import unquote

class Radio:
    """The radio-bot related commands."""

    def __init__(self, bot):
        self.bot = bot
        if not discord.opus.is_loaded():
            discord.opus.load_opus('/usr/local/lib/libopus.so') #FreeBSD path

        self.player = None
        self.stopped = True
        self.break_loop = asyncio.Event()
        #self.break_loop.clear()
        self.q = asyncio.Queue()
        self.play_next_song = asyncio.Event()
        self.current_song = None
        self.songs_dir = 'radio/'
        self.songs = []
        self.playlists = {}
        self.update_song_list()

    @property
    def is_playing(self):
        return self.player is not None and self.player.is_playing() and not self.stopped

    def toggle_next_song(self):
        if not self.stopped:
            self.bot.loop.call_soon_threadsafe(self.play_next_song.set)

    def update_song_list(self):
        self.songs = self.bot.yadisk.list_files(self.songs_dir)
        self.update_playlists()

    def update_playlists(self):
        pl_files = self.bot.yadisk.list_files(self.songs_dir + 'playlists/')
        for pl in pl_files:
            pl_url = self.bot.yadisk.direct_link(self.songs_dir + 'playlists/' + pl)
            pl_data = self.bot.yadisk._get(pl_url).json()['songs']
            self.playlists[pl] = []
            for song in pl_data:
                if song in self.songs:
                    self.playlists[pl].append(song)

    @commands.command(pass_context=True)
    async def join(self, ctx, *, channel_name : str):
        """Зайти на указанный голосовой канал."""
        if self.bot.is_voice_connected():
            await ctx.invoke(self.leave)

        check = lambda c: c.name == channel_name and c.type == discord.ChannelType.voice
        channel = discord.utils.find(check, ctx.message.server.channels)
        if channel is None:
            await self.bot.say('Нет такого голосового канала.')
        await self.bot.join_voice_channel(channel)

    @commands.command(pass_context=True)
    async def leave(self, ctx):
        """Покинуть текущий голосовой канал."""
        await ctx.invoke(self.stop)
        await self.bot.voice.disconnect()

    @commands.command()
    async def pause(self):
        """Приостановить воспроизведение."""
        if self.player is not None:
            self.player.pause()

    @commands.command()
    async def resume(self):
        """Продолжить воспроизведение."""
        if self.player is not None and not self.is_playing:
            self.player.resume()

    @commands.command()
    async def skip(self):
        """Перейти к следующей песне в очереди."""
        if self.player is not None and self.is_playing:
            self.player.stop()
            self.toggle_next_song()

    @commands.command()
    async def stop(self):
        """Остановить воспроизведение."""
        if self.is_playing:
            self.break_loop.set()
            self.play_next_song.set()
            self.stopped = True
            self.player.stop()

    @commands.command(pass_context=True)
    async def play(self, ctx):
        """Начать воспроизведение песен из очереди."""
        if self.player is not None and not self.stopped:
            if not self.is_playing:
                await ctx.invoke(self.resume)
                return
            else:
                await self.bot.say('Уже играю песенку.')
                return

        while True:
            if not self.bot.is_voice_connected():
                author_channel = ctx.message.author.voice_channel
                if author_channel is not None:
                    print('Joining {}.'.format(author_channel.name))
                    await ctx.invoke(self.join, channel_name=author_channel.name)
                else:
                    await self.bot.say('Не выбран голосовой канал.')
                    return

            if self.q.empty():
                await self.q.put(random.choice(self.songs))
            self.play_next_song.clear()
            self.current = await self.q.get()
            self.player = self.bot.voice.create_ffmpeg_player(
                self.bot.yadisk.direct_link(self.songs_dir + self.current),
                after=self.toggle_next_song)
                #options="-loglevel debug -report",
                #headers = dict(self.bot.pycopy.session.headers)
            self.stopped = False
            self.player.start()
            song_name = unquote(self.current.split('/')[-1])
            await self.bot.change_status(discord.Game(name=song_name))

            await self.play_next_song.wait()
            if self.break_loop.is_set():
                self.break_loop.clear()
                return
        await self.bot.say('Leaving play loop')

    @commands.command(aliases=['c'])
    async def current(self):
        """Что там играет?"""
        if self.is_playing:
            song_name = unquote(self.current.split('/')[-1])
            await self.bot.say(song_name)

    @commands.command()
    async def update(self):
        """Обновить список песен."""
        self.update_song_list()
        await self.bot.say("Найдено {} песенок".format(len(self.songs)))

    @commands.command()
    async def list(self):
        """Вывести список всех доступных песен."""
        song_list = ""
        id = 1
        for song in self.songs:
            song_list += "{}. {}\n".format(id, song)
            id += 1
            if len(song_list) > 1800:
                await self.bot.say(song_list)
                song_list = ''
        await self.bot.say(song_list)

    @commands.command(aliases=['ss'])
    async def searchsong(self, search_word : str):
        """Искать песню по названию."""
        search_result = ""
        id = 1
        found = False
        for song in self.songs:
            if search_word.lower() in song.lower():
                found = True
                search_result += "{}. {}\n".format(id, song)
                if len(search_result) > 1800:
                    await self.bot.say(search_result)
                    search_result = ''
            id += 1
        if not found:
            search_result = "Нет такой песни."
        await self.bot.say(search_result)

    @commands.command()
    async def add(self, song_num : int):
        """Добавить в конец очереди песню с данным номером."""
        await self.q.put(self.songs[song_num-1])
        await self.bot.say("{} будет следующей песенкой".format(self.songs[song_num-1]))

    @commands.group(pass_context=True, aliases=['pl'])
    async def playlist(self):
        await self.bot.say(self.playlists)

    @playlist.command(aliases=['add'])
    async def pl_add(self, song : int, playlist : str):
        if not playlist in self.playlists:
            await ctx.invoke(self.new, playlist=playlist)
        try:
            self.playlists[playlist].append(self.songs[song-1])
        except:
            await self.bot.say('Нет такой песенки')
            return
        pl_json = {'name': playlist, 'songs': self.playlists[playlist]}
        self.bot.yadisk.upload(self.songs_dir + 'playlists' + playlist, json.dumps(pl_json))

def setup(bot):
    bot.add_cog(Radio(bot))
<|endoftext|>


<commit_before>"""
Cycler
======

Cycling through combinations of values, producing dictionaries.

You can add cyclers::

    from cycler import cycler
    cc = (cycler(color=list('rgb')) +
          cycler(linestyle=['-', '--', '-.']))
    for d in cc:
        print(d)

Results in::

    {'color': 'r', 'linestyle': '-'}
    {'color': 'g', 'linestyle': '--'}
    {'color': 'b', 'linestyle': '-.'}

You can multiply cyclers::

    from cycler import cycler
    cc = (cycler(color=list('rgb')) *
          cycler(linestyle=['-', '--', '-.']))
    for d in cc:
        print(d)

Results in::

    {'color': 'r', 'linestyle': '-'}
    {'color': 'r', 'linestyle': '--'}
    {'color': 'r', 'linestyle': '-.'}
    {'color': 'g', 'linestyle': '-'}
    {'color': 'g', 'linestyle': '--'}
    {'color': 'g', 'linestyle': '-.'}
    {'color': 'b', 'linestyle': '-'}
    {'color': 'b', 'linestyle': '--'}
    {'color': 'b', 'linestyle': '-.'}
"""

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import copy
from functools import reduce
from itertools import product, cycle
from operator import mul, add
import sys

if sys.version_info < (3,):
    from itertools import izip as zip

__version__ = '0.10.0'

def _process_keys(left, right):
    """
    Helper function to compose cycler keys.

    Parameters
    ----------
    left, right : iterable of dictionaries or None
        The cyclers to be composed.

    Returns
    -------
    keys : set
        The keys in the composition of the two cyclers.
    """
    l_peek = next(iter(left)) if left is not None else {}
    r_peek = next(iter(right)) if right is not None else {}
    l_key = set(l_peek.keys())
    r_key = set(r_peek.keys())
    if l_key & r_key:
        raise ValueError("Can not compose overlapping cycles")
    return l_key | r_key

def concat(left, right):
    r"""
    Concatenate `Cycler`\s, as if chained using `itertools.chain`.

    The keys must match exactly.

    Examples
    --------
    >>> num = cycler('a', range(3))
    >>> let = cycler('a', 'abc')
    >>> num.concat(let)
    cycler('a', [0, 1, 2, 'a', 'b', 'c'])

    Returns
    -------
    `Cycler`
        The concatenated cycler.
    """
    if left.keys != right.keys:
        raise ValueError("Keys do not match:\n"
                         "\tIntersection: {both!r}\n"
                         "\tDisjoint: {just_one!r}".format(
                             both=left.keys & right.keys,
                             just_one=left.keys ^ right.keys))
    _l = left.by_key()
    _r = right.by_key()
    return reduce(add, (_cycler(k, _l[k] + _r[k]) for k in left.keys))

class Cycler(object):
    """
    Composable cycles.

    This class has compositions methods:

    ``+``
      for 'inner' products (zip)

    ``+=``
      in-place ``+``

    ``*``
      for outer products (`itertools.product`) and integer multiplication

    ``*=``
      in-place ``*``

    and supports basic slicing via ``[]``.

    Parameters
    ----------
    left, right : Cycler or None
        The 'left' and 'right' cyclers.
    op : func or None
        Function which composes the 'left' and 'right' cyclers.
    """

    def __call__(self):
        return cycle(self)

    def __init__(self, left, right=None, op=None):
        """
        Semi-private init.

        Do not use this directly, use `cycler` function instead.
        """
        if isinstance(left, Cycler):
            self._left = Cycler(left._left, left._right, left._op)
        elif left is not None:
            # Need to copy the dictionary or else that will be a residual
            # mutable that could lead to strange errors
            self._left = [copy.copy(v) for v in left]
        else:
            self._left = None

        if isinstance(right, Cycler):
            self._right = Cycler(right._left, right._right, right._op)
        elif right is not None:
            # Need to copy the dictionary or else that will be a residual
            # mutable that could lead to strange errors
            self._right = [copy.copy(v) for v in right]
        else:
            self._right = None

        self._keys = _process_keys(self._left, self._right)
        self._op = op

    def __contains__(self, k):
        return k in self._keys

    @property
    def keys(self):
        """The keys this Cycler knows about."""
        return set(self._keys)

    def change_key(self, old, new):
        """
        Change a key in this cycler to a new name.
        Modification is performed in-place.

        Does nothing if the old key is the same as the new key.
        Raises a ValueError if the new key is already a key.
        Raises a KeyError if the old key isn't a key.
        """
        if old == new:
            return
        if new in self._keys:
            raise ValueError("Can't replace {} with {}, {} is already a key"
                             .format(old, new, new))
        if old not in self._keys:
            raise KeyError("Can't replace {} with {}, {} is not a key"
                           .format(old, new, old))

        self._keys.remove(old)
        self._keys.add(new)

        if self._right is not None and old in self._right.keys:
            self._right.change_key(old, new)

        # self._left should always be non-None
        # if self._keys is non-empty.
        elif isinstance(self._left, Cycler):
            self._left.change_key(old, new)
        else:
            # It should be completely safe at this point to
            # assume that the old key can be found in each
            # iteration.
            self._left = [{new: entry[old]} for entry in self._left]

    @classmethod
    def _from_iter(cls, label, itr):
        """
        Class method to create 'base' Cycler objects
        that do not have a 'right' or 'op' and for which
        the 'left' object is not another Cycler.

        Parameters
        ----------
        label : str
            The property key.

        itr : iterable
            Finite length iterable of the property values.

        Returns
        -------
        `Cycler`
            New 'base' cycler.
        """
        ret = cls(None)
        ret._left = list({label: v} for v in itr)
        ret._keys = set([label])
        return ret

    def __getitem__(self, key):
        # TODO : maybe add numpy style fancy slicing
        if isinstance(key, slice):
            trans = self.by_key()
            return reduce(add, (_cycler(k, v[key]) for k, v in trans.items()))
        else:
            raise ValueError("Can only use slices with Cycler.__getitem__")

    def __iter__(self):
        if self._right is None:
            for left in self._left:
                yield dict(left)
        else:
            for a, b in self._op(self._left, self._right):
                out = {}
                out.update(a)
                out.update(b)
                yield out

    def __add__(self, other):
        """
        Pair-wise combine two equal length cyclers (zip).

        Parameters
        ----------
        other : Cycler
        """
        if len(self) != len(other):
            raise ValueError("Can only add equal length cycles, "
                             "not {0} and {1}".format(len(self), len(other)))
        return Cycler(self, other, zip)

    def __mul__(self, other):
        """
        Outer product of two cyclers (`itertools.product`) or integer
        multiplication.

        Parameters
        ----------
        other : Cycler or int
        """
        if isinstance(other, Cycler):
            return Cycler(self, other, product)
        elif isinstance(other, int):
            trans = self.by_key()
            return reduce(add, (_cycler(k, v*other) for k, v in trans.items()))
        else:
            return NotImplemented

    def __rmul__(self, other):
        return self * other

    def __len__(self):
        op_dict = {zip: min, product: mul}
        if self._right is None:
            return len(self._left)
        l_len = len(self._left)
        r_len = len(self._right)
        return op_dict[self._op](l_len, r_len)

    def __iadd__(self, other):
        """
        In-place pair-wise combine two equal length cyclers (zip).

        Parameters
        ----------
        other : Cycler
        """
        if not isinstance(other, Cycler):
            raise TypeError("Cannot += with a non-Cycler object")
        # True shallow copy of self is fine since this is in-place
        old_self = copy.copy(self)
        self._keys = _process_keys(old_self, other)
        self._left = old_self
        self._op = zip
        self._right = Cycler(other._left, other._right, other._op)
        return self

    def __imul__(self, other):
        """
        In-place outer product of two cyclers (`itertools.product`).

        Parameters
        ----------
        other : Cycler
        """
        if not isinstance(other, Cycler):
            raise TypeError("Cannot *= with a non-Cycler object")
        # True shallow copy of self is fine since this is in-place
        old_self = copy.copy(self)
        self._keys = _process_keys(old_self, other)
        self._left = old_self
        self._op = product
        self._right = Cycler(other._left, other._right, other._op)
        return self

    def __eq__(self, other):
        if len(self) != len(other):
            return False
        if self.keys ^ other.keys:
            return False
        return all(a == b for a, b in zip(self, other))

    def __ne__(self, other):
        return not (self == other)

    __hash__ = None

    def __repr__(self):
        op_map = {zip: '+', product: '*'}
        if self._right is None:
            lab = self.keys.pop()
            itr = list(v[lab] for v in self)
            return "cycler({lab!r}, {itr!r})".format(lab=lab, itr=itr)
        else:
            op = op_map.get(self._op, '?')
            msg = "({left!r} {op} {right!r})"
            return msg.format(left=self._left, op=op, right=self._right)

    def _repr_html_(self):
        # an table showing the value of each key through a full cycle
        output = "
"
        sorted_keys = sorted(self.keys, key=repr)
        for key in sorted_keys:
            output += "{key!r}	".format(key=key)
        for d in iter(self):
            output += "
"
            for k in sorted_keys:
                output += "{val!r}	".format(val=d[k])
            output += "
"
        output += "
"
        return output

    def by_key(self):
        """
        Values by key.

        This returns the transposed values of the cycler.  Iterating
        over a `Cycler` yields dicts with a single value for each key,
        this method returns a `dict` of `list` which are the values
        for the given key.

        The returned value can be used to create an equivalent `Cycler`
        using only `+`.

        Returns
        -------
        transpose : dict
            dict of lists of the values for each key.
        """

        # TODO : sort out if this is a bottle neck, if there is a better way
        # and if we care.

        keys = self.keys
        out = {k: list() for k in keys}

        for d in self:
            for k in keys:
                out[k].append(d[k])
        return out

    # for back compatibility
    _transpose = by_key

    def simplify(self):
        """
        Simplify the cycler into a sum (but no products) of cyclers.

        Returns
        -------
        simple : Cycler
        """
        # TODO: sort out if it is worth the effort to make sure this is
        # balanced.  Currently it is is
        # (((a + b) + c) + d) vs
        # ((a + b) + (c + d))
        # I would believe that there is some performance implications
        trans = self.by_key()
        return reduce(add, (_cycler(k, v) for k, v in trans.items()))

    concat = concat

def cycler(*args, **kwargs):
    """
    Create a new `Cycler` object from a single positional argument,
    a pair of positional arguments, or the combination of keyword arguments.

    cycler(arg)
    cycler(label1=itr1[, label2=iter2[, ...]])
    cycler(label, itr)

    Form 1 simply copies a given `Cycler` object.

    Form 2 composes a `Cycler` as an inner product of the
    pairs of keyword arguments. In other words, all of the
    iterables are cycled simultaneously, as if through zip().

    Form 3 creates a `Cycler` from a label and an iterable.
    This is useful for when the label cannot be a keyword argument
    (e.g., an integer or a name that has a space in it).

    Parameters
    ----------
    arg : Cycler
        Copy constructor for Cycler (does a shallow copy of iterables).
    label : name
        The property key. In the 2-arg form of the function,
        the label can be any hashable object. In the keyword argument
        form of the function, it must be a valid python identifier.
    itr : iterable
        Finite length iterable of the property values.
        Can be a single-property `Cycler` that would
        be like a key change, but as a shallow copy.

    Returns
    -------
    cycler : Cycler
        New `Cycler` for the given property

    """
    if args and kwargs:
        raise TypeError("cyl() can only accept positional OR keyword "
                        "arguments -- not both.")

    if len(args) == 1:
        if not isinstance(args[0], Cycler):
            raise TypeError("If only one positional argument given, it must "
                            "be a Cycler instance.")
        return Cycler(args[0])
    elif len(args) == 2:
        return _cycler(*args)
    elif len(args) > 2:
        raise TypeError("Only a single Cycler can be accepted as the lone "
                        "positional argument. Use keyword arguments instead.")

    if kwargs:
        return reduce(add, (_cycler(k, v) for k, v in kwargs.items()))

    raise TypeError("Must have at least a positional OR keyword arguments")

def _cycler(label, itr):
    """
    Create a new `Cycler` object from a property name and iterable of values.

    Parameters
    ----------
    label : hashable
        The property key.
    itr : iterable
        Finite length iterable of the property values.

    Returns
    -------
    cycler : Cycler
        New `Cycler` for the given property
    """
    if isinstance(itr, Cycler):
        keys = itr.keys
        if len(keys) != 1:
            msg = "Can not create Cycler from a multi-property Cycler"
            raise ValueError(msg)

        lab = keys.pop()
        # Doesn't need to be a new list because
        # _from_iter() will be creating that new list anyway.
        itr = (v[lab] for v in itr)

    return Cycler._from_iter(label, itr)
<commit_msg>changed formatting with named placeholders<commit_after>"""
Cycler
======

Cycling through combinations of values, producing dictionaries.

You can add cyclers::

    from cycler import cycler
    cc = (cycler(color=list('rgb')) +
          cycler(linestyle=['-', '--', '-.']))
    for d in cc:
        print(d)

Results in::

    {'color': 'r', 'linestyle': '-'}
    {'color': 'g', 'linestyle': '--'}
    {'color': 'b', 'linestyle': '-.'}

You can multiply cyclers::

    from cycler import cycler
    cc = (cycler(color=list('rgb')) *
          cycler(linestyle=['-', '--', '-.']))
    for d in cc:
        print(d)

Results in::

    {'color': 'r', 'linestyle': '-'}
    {'color': 'r', 'linestyle': '--'}
    {'color': 'r', 'linestyle': '-.'}
    {'color': 'g', 'linestyle': '-'}
    {'color': 'g', 'linestyle': '--'}
    {'color': 'g', 'linestyle': '-.'}
    {'color': 'b', 'linestyle': '-'}
    {'color': 'b', 'linestyle': '--'}
    {'color': 'b', 'linestyle': '-.'}
"""

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import copy
from functools import reduce
from itertools import product, cycle
from operator import mul, add
import sys

if sys.version_info < (3,):
    from itertools import izip as zip

__version__ = '0.10.0'

def _process_keys(left, right):
    """
    Helper function to compose cycler keys.

    Parameters
    ----------
    left, right : iterable of dictionaries or None
        The cyclers to be composed.

    Returns
    -------
    keys : set
        The keys in the composition of the two cyclers.
    """
    l_peek = next(iter(left)) if left is not None else {}
    r_peek = next(iter(right)) if right is not None else {}
    l_key = set(l_peek.keys())
    r_key = set(r_peek.keys())
    if l_key & r_key:
        raise ValueError("Can not compose overlapping cycles")
    return l_key | r_key

def concat(left, right):
    r"""
    Concatenate `Cycler`\s, as if chained using `itertools.chain`.

    The keys must match exactly.

    Examples
    --------
    >>> num = cycler('a', range(3))
    >>> let = cycler('a', 'abc')
    >>> num.concat(let)
    cycler('a', [0, 1, 2, 'a', 'b', 'c'])

    Returns
    -------
    `Cycler`
        The concatenated cycler.
    """
    if left.keys != right.keys:
        raise ValueError("Keys do not match:\n"
                         "\tIntersection: {both!r}\n"
                         "\tDisjoint: {just_one!r}".format(
                             both=left.keys & right.keys,
                             just_one=left.keys ^ right.keys))
    _l = left.by_key()
    _r = right.by_key()
    return reduce(add, (_cycler(k, _l[k] + _r[k]) for k in left.keys))

class Cycler(object):
    """
    Composable cycles.

    This class has compositions methods:

    ``+``
      for 'inner' products (zip)

    ``+=``
      in-place ``+``

    ``*``
      for outer products (`itertools.product`) and integer multiplication

    ``*=``
      in-place ``*``

    and supports basic slicing via ``[]``.

    Parameters
    ----------
    left, right : Cycler or None
        The 'left' and 'right' cyclers.
    op : func or None
        Function which composes the 'left' and 'right' cyclers.
    """

    def __call__(self):
        return cycle(self)

    def __init__(self, left, right=None, op=None):
        """
        Semi-private init.

        Do not use this directly, use `cycler` function instead.
        """
        if isinstance(left, Cycler):
            self._left = Cycler(left._left, left._right, left._op)
        elif left is not None:
            # Need to copy the dictionary or else that will be a residual
            # mutable that could lead to strange errors
            self._left = [copy.copy(v) for v in left]
        else:
            self._left = None

        if isinstance(right, Cycler):
            self._right = Cycler(right._left, right._right, right._op)
        elif right is not None:
            # Need to copy the dictionary or else that will be a residual
            # mutable that could lead to strange errors
            self._right = [copy.copy(v) for v in right]
        else:
            self._right = None

        self._keys = _process_keys(self._left, self._right)
        self._op = op

    def __contains__(self, k):
        return k in self._keys

    @property
    def keys(self):
        """The keys this Cycler knows about."""
        return set(self._keys)

    def change_key(self, old, new):
        """
        Change a key in this cycler to a new name.
        Modification is performed in-place.

        Does nothing if the old key is the same as the new key.
        Raises a ValueError if the new key is already a key.
        Raises a KeyError if the old key isn't a key.
        """
        if old == new:
            return
        if new in self._keys:
            raise ValueError("Can't replace {old} with {new}, {new} is already a key"
                             .format(old, new, new))
        if old not in self._keys:
            raise KeyError("Can't replace {old} with {new}, {old} is not a key"
                           .format(old, new, old))

        self._keys.remove(old)
        self._keys.add(new)

        if self._right is not None and old in self._right.keys:
            self._right.change_key(old, new)

        # self._left should always be non-None
        # if self._keys is non-empty.
        elif isinstance(self._left, Cycler):
            self._left.change_key(old, new)
        else:
            # It should be completely safe at this point to
            # assume that the old key can be found in each
            # iteration.
            self._left = [{new: entry[old]} for entry in self._left]

    @classmethod
    def _from_iter(cls, label, itr):
        """
        Class method to create 'base' Cycler objects
        that do not have a 'right' or 'op' and for which
        the 'left' object is not another Cycler.

        Parameters
        ----------
        label : str
            The property key.

        itr : iterable
            Finite length iterable of the property values.

        Returns
        -------
        `Cycler`
            New 'base' cycler.
        """
        ret = cls(None)
        ret._left = list({label: v} for v in itr)
        ret._keys = set([label])
        return ret

    def __getitem__(self, key):
        # TODO : maybe add numpy style fancy slicing
        if isinstance(key, slice):
            trans = self.by_key()
            return reduce(add, (_cycler(k, v[key]) for k, v in trans.items()))
        else:
            raise ValueError("Can only use slices with Cycler.__getitem__")

    def __iter__(self):
        if self._right is None:
            for left in self._left:
                yield dict(left)
        else:
            for a, b in self._op(self._left, self._right):
                out = {}
                out.update(a)
                out.update(b)
                yield out

    def __add__(self, other):
        """
        Pair-wise combine two equal length cyclers (zip).

        Parameters
        ----------
        other : Cycler
        """
        if len(self) != len(other):
            raise ValueError("Can only add equal length cycles, "
                             "not {0} and {1}".format(len(self), len(other)))
        return Cycler(self, other, zip)

    def __mul__(self, other):
        """
        Outer product of two cyclers (`itertools.product`) or integer
        multiplication.

        Parameters
        ----------
        other : Cycler or int
        """
        if isinstance(other, Cycler):
            return Cycler(self, other, product)
        elif isinstance(other, int):
            trans = self.by_key()
            return reduce(add, (_cycler(k, v*other) for k, v in trans.items()))
        else:
            return NotImplemented

    def __rmul__(self, other):
        return self * other

    def __len__(self):
        op_dict = {zip: min, product: mul}
        if self._right is None:
            return len(self._left)
        l_len = len(self._left)
        r_len = len(self._right)
        return op_dict[self._op](l_len, r_len)

    def __iadd__(self, other):
        """
        In-place pair-wise combine two equal length cyclers (zip).

        Parameters
        ----------
        other : Cycler
        """
        if not isinstance(other, Cycler):
            raise TypeError("Cannot += with a non-Cycler object")
        # True shallow copy of self is fine since this is in-place
        old_self = copy.copy(self)
        self._keys = _process_keys(old_self, other)
        self._left = old_self
        self._op = zip
        self._right = Cycler(other._left, other._right, other._op)
        return self

    def __imul__(self, other):
        """
        In-place outer product of two cyclers (`itertools.product`).

        Parameters
        ----------
        other : Cycler
        """
        if not isinstance(other, Cycler):
            raise TypeError("Cannot *= with a non-Cycler object")
        # True shallow copy of self is fine since this is in-place
        old_self = copy.copy(self)
        self._keys = _process_keys(old_self, other)
        self._left = old_self
        self._op = product
        self._right = Cycler(other._left, other._right, other._op)
        return self

    def __eq__(self, other):
        if len(self) != len(other):
            return False
        if self.keys ^ other.keys:
            return False
        return all(a == b for a, b in zip(self, other))

    def __ne__(self, other):
        return not (self == other)

    __hash__ = None

    def __repr__(self):
        op_map = {zip: '+', product: '*'}
        if self._right is None:
            lab = self.keys.pop()
            itr = list(v[lab] for v in self)
            return "cycler({lab!r}, {itr!r})".format(lab=lab, itr=itr)
        else:
            op = op_map.get(self._op, '?')
            msg = "({left!r} {op} {right!r})"
            return msg.format(left=self._left, op=op, right=self._right)

    def _repr_html_(self):
        # an table showing the value of each key through a full cycle
        output = "
"
        sorted_keys = sorted(self.keys, key=repr)
        for key in sorted_keys:
            output += "{key!r}	".format(key=key)
        for d in iter(self):
            output += "
"
            for k in sorted_keys:
                output += "{val!r}	".format(val=d[k])
            output += "
"
        output += "
"
        return output

    def by_key(self):
        """
        Values by key.

        This returns the transposed values of the cycler.  Iterating
        over a `Cycler` yields dicts with a single value for each key,
        this method returns a `dict` of `list` which are the values
        for the given key.

        The returned value can be used to create an equivalent `Cycler`
        using only `+`.

        Returns
        -------
        transpose : dict
            dict of lists of the values for each key.
        """

        # TODO : sort out if this is a bottle neck, if there is a better way
        # and if we care.

        keys = self.keys
        out = {k: list() for k in keys}

        for d in self:
            for k in keys:
                out[k].append(d[k])
        return out

    # for back compatibility
    _transpose = by_key

    def simplify(self):
        """
        Simplify the cycler into a sum (but no products) of cyclers.

        Returns
        -------
        simple : Cycler
        """
        # TODO: sort out if it is worth the effort to make sure this is
        # balanced.  Currently it is is
        # (((a + b) + c) + d) vs
        # ((a + b) + (c + d))
        # I would believe that there is some performance implications
        trans = self.by_key()
        return reduce(add, (_cycler(k, v) for k, v in trans.items()))

    concat = concat

def cycler(*args, **kwargs):
    """
    Create a new `Cycler` object from a single positional argument,
    a pair of positional arguments, or the combination of keyword arguments.

    cycler(arg)
    cycler(label1=itr1[, label2=iter2[, ...]])
    cycler(label, itr)

    Form 1 simply copies a given `Cycler` object.

    Form 2 composes a `Cycler` as an inner product of the
    pairs of keyword arguments. In other words, all of the
    iterables are cycled simultaneously, as if through zip().

    Form 3 creates a `Cycler` from a label and an iterable.
    This is useful for when the label cannot be a keyword argument
    (e.g., an integer or a name that has a space in it).

    Parameters
    ----------
    arg : Cycler
        Copy constructor for Cycler (does a shallow copy of iterables).
    label : name
        The property key. In the 2-arg form of the function,
        the label can be any hashable object. In the keyword argument
        form of the function, it must be a valid python identifier.
    itr : iterable
        Finite length iterable of the property values.
        Can be a single-property `Cycler` that would
        be like a key change, but as a shallow copy.

    Returns
    -------
    cycler : Cycler
        New `Cycler` for the given property

    """
    if args and kwargs:
        raise TypeError("cyl() can only accept positional OR keyword "
                        "arguments -- not both.")

    if len(args) == 1:
        if not isinstance(args[0], Cycler):
            raise TypeError("If only one positional argument given, it must "
                            "be a Cycler instance.")
        return Cycler(args[0])
    elif len(args) == 2:
        return _cycler(*args)
    elif len(args) > 2:
        raise TypeError("Only a single Cycler can be accepted as the lone "
                        "positional argument. Use keyword arguments instead.")

    if kwargs:
        return reduce(add, (_cycler(k, v) for k, v in kwargs.items()))

    raise TypeError("Must have at least a positional OR keyword arguments")

def _cycler(label, itr):
    """
    Create a new `Cycler` object from a property name and iterable of values.

    Parameters
    ----------
    label : hashable
        The property key.
    itr : iterable
        Finite length iterable of the property values.

    Returns
    -------
    cycler : Cycler
        New `Cycler` for the given property
    """
    if isinstance(itr, Cycler):
        keys = itr.keys
        if len(keys) != 1:
            msg = "Can not create Cycler from a multi-property Cycler"
            raise ValueError(msg)

        lab = keys.pop()
        # Doesn't need to be a new list because
        # _from_iter() will be creating that new list anyway.
        itr = (v[lab] for v in itr)

    return Cycler._from_iter(label, itr)
<|endoftext|>


<commit_before>#/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2010-2012 Cidadania S. Coop. Galega
#
# This file is part of e-cidadania.
#
# e-cidadania is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# e-cidadania is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with e-cidadania. If not, see <http://www.gnu.org/licenses/>.

from core.spaces import url_names
from core.spaces.models import Space

from tests.test_utils import ECDTestCase

class ViewSpaceIndexTest(ECDTestCase):

    """
    Tests the view for the index page of a space.
    """

    def setUp(self):
        super(ViewSpaceIndexTest, self).init()
        self.private_space = self.foo_space
        self.private_space_url = self.getURL(url_names.SPACE_INDEX,
                                        kwargs={'space_url': self.private_space.url})
        self.public_space = self.bar_space
        self.public_space_url = self.getURL(url_names.SPACE_INDEX,
                                            kwargs={'space_url': self.public_space.url})

    def testAnonymousUserCanNotAccessPrivateSpace(self):
        """
        Tests if anonymous user can not access the space index page.
        """
        response = self.get(self.private_space_url)
        self.assertResponseOK(response)
        self.assertContains(response, "You're an anonymous user.")

    def testUnregisteredUserCanNotAccessPrivateSpace(self):
        """Tests if an unregistered user can not access the space index.
        """
        #Create and login a user who is not registered to the space
        user = self.login("test_user", "test_password")
        self.assertFalse(user.is_staff)
        self.assertFalse(user.is_superuser)
        self.assertFalse(user.is_anonymous())
        self.assertFalse(user in self.private_space.users.all())
        self.assertFalse(user in self.private_space.mods.all())
        self.assertFalse(user in self.private_space.admins.all())
        response = self.get(self.private_space_url)
        self.assertResponseOK(response)
        self.assertContains(response, "You're not registered to this             space.")
        self.logout()

    def testSpaceAdminCanAccessThePrivateSpace(self):
        """Tests if the space admin can access the space index.
        """
        space_admin = self.login('foo_admin', 'foo_admin_password')
        self.assertTrue(self.isLoggedIn(space_admin))

        response = self.get(self.private_space_url)
        self.assertResponseOK(response)
        self.assertTemplateNotUsed(response, 'not_allowed.html')
        self.logout()

    def testSpaceModCanAccessThePrivateSpace(self):
        """Tests if the space mod can access the space index.
        """
        space_mod = self.login('foo_mod', 'foo_mod_password')
        self.assertTrue(self.isLoggedIn(space_mod))
        response = self.get(self.private_space_url)
        self.assertResponseOK(response)
        self.assertTemplateNotUsed(response, 'not_allowed.html')
        self.logout()

    def testSpaceUserCanAccessTheSpace(self):
        """Tests if the space user can access the space index.
        """
        space_user =  self.login('foo_user', 'foo_user_password')
        self.assertTrue(self.isLoggedIn(space_user))
        response = self.get(self.private_space_url)
        self.assertResponseOK(response)
        self.assertTemplateNotUsed(response, 'not_allowed.html')
        self.logout()

    def testOtherUsersCanNotAccessThePrivateSpace(self):
        """Test if other users who are not registered to the space can not
        access the space.
        """
        other_user = self.login('bar_admin', 'bar_admin_password')
        self.assertTrue(self.isLoggedIn(other_user))
        self.assertFalse(other_user in self.private_space.admins.all())
        response = self.get(self.private_space_url)
        self.assertResponseOK(response)
        self.assertTemplateUsed(response, 'not_allowed.html')

    def testAdminAccessToAPublicSpace(self):
        """Tests if an admin for one space can access a public space.
        """
        admin = self.login('foo_admin', 'foo_admin_password')
        self.assertTrue(self.isLoggedIn(admin))
        self.assertFalse(admin in self.public_space.admins.all())
        response = self.get(self.public_space_url)
        self.assertResponseOK(response)
        self.assertTemplateNotUsed(response, 'not_allowed.html')

    def testAnonymousUserCanAcessAPublicSpace(self):
        """Tests if an anonymous user can access a public space.
        """
        response = self.get(self.public_space_url)
        self.assertResponseOK(response)
        self.assertTemplateNotUsed(response, 'not_allowed.html')

class DeleteSpaceTest(ECDTestCase):
    """
    Tests the deletion of a space.
    """

    def setUp(self):
        self.init()

    def testGeneralUserAccess(self):
        """
        Tests if a general user is prohibited from deleting the space.
        """
        space = self.bar_space
        general_user = self.login('test_user', 'test_password')
        url = self.getURL(url_names.SPACE_DELETE, kwargs={'space_url': space.url})
        response = self.get(url)
        self.assertResponseRedirect(response)
        self.assertEqual(url, response.request['PATH_INFO'])

    def testAdminAccess(self):
        """
        Tests if a correct admin can delete a space.
        """
        space =self.bar_space
        user = self.create_super_user("other_admin", "other_password",
                                      logged_in=True)
        self.assertTrue(self.isLoggedIn(user))

        url = self.getURL(url_names.SPACE_DELETE, kwargs={'space_url': space.url})
        response = self.get(url)
        self.assertResponseOK(response)
        self.assertTemplateUsed(response, 'not_allowed.html')

        #logout the present user because the space does not belong to it
        self.logout()
        admin = self.login('bar_admin', 'bar_admin_password')
        self.assertTrue(self.isLoggedIn(admin))
        self.assertTrue(admin in space.admins.all())
        response = self.get(url)
        self.assertResponseRedirect(response)
        self.assertTemplateNotUsed(response, 'not_allowed.html')

class ListSpacesTest(ECDTestCase):
    """
    Tests the list spaces view.
    """

    def setUp(self):
        self.init()
        #We have a public space as well as a private space.
        self.private_space = self.foo_space
        self.public_space = self.bar_space
        self.url = self.getURL(url_names.SPACE_LIST)

    def testOnlyPublicSpacesAreListedForAnonymousUser(self):
        """
        Tests if only the public spaces are listed for anonymous user.
        """
        #No user is logged in currently
        response = self.get(self.url)
        self.assertResponseOK(response)
        spaces_returned = response.context[0].dicts[0]['space_list']
        self.assertEqual(len(spaces_returned), 1)
        self.assertTrue(self.public_space in spaces_returned)
        self.assertTrue(self.private_space not in spaces_returned)

    def testAllSpacesAreReturnedForALoggedInUser(self):
        """
        Tests if both the public and private spaces are returned for a logged
        in user who is registered for both the spaces.

        We make self.bar_admin to be a user for self.foo_space which is a
        private space.
        """
        self.foo_space.users.add(self.bar_admin)
        self.login('bar_admin', 'bar_admin_password')
        response = self.get(self.url)
        spaces_returned = response.context[0].dicts[0]['spaces_list']
        self.assertEqual(len(spaces_returned), 2)
        self.assertTrue(self.foo_space in spaces_returned)
        self.assertTrue(self.bar_space in spaces_returned)

<commit_msg>similar error<commit_after>#/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2010-2012 Cidadania S. Coop. Galega
#
# This file is part of e-cidadania.
#
# e-cidadania is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# e-cidadania is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with e-cidadania. If not, see <http://www.gnu.org/licenses/>.

from core.spaces import url_names
from core.spaces.models import Space

from tests.test_utils import ECDTestCase

class ViewSpaceIndexTest(ECDTestCase):

    """
    Tests the view for the index page of a space.
    """

    def setUp(self):
        super(ViewSpaceIndexTest, self).init()
        self.private_space = self.foo_space
        self.private_space_url = self.getURL(url_names.SPACE_INDEX,
                                        kwargs={'space_url': self.private_space.url})
        self.public_space = self.bar_space
        self.public_space_url = self.getURL(url_names.SPACE_INDEX,
                                            kwargs={'space_url': self.public_space.url})

    def testAnonymousUserCanNotAccessPrivateSpace(self):
        """
        Tests if anonymous user can not access the space index page.
        """
        response = self.get(self.private_space_url)
        self.assertResponseOK(response)
        self.assertContains(response, "You're an anonymous user.")

    def testUnregisteredUserCanNotAccessPrivateSpace(self):
        """Tests if an unregistered user can not access the space index.
        """
        #Create and login a user who is not registered to the space
        user = self.login("test_user", "test_password")
        self.assertFalse(user.is_staff)
        self.assertFalse(user.is_superuser)
        self.assertFalse(user.is_anonymous())
        self.assertFalse(user in self.private_space.users.all())
        self.assertFalse(user in self.private_space.mods.all())
        self.assertFalse(user in self.private_space.admins.all())
        response = self.get(self.private_space_url)
        self.assertResponseOK(response)
        self.assertContains(response, "You're not registered to this             space.")
        self.logout()

    def testSpaceAdminCanAccessThePrivateSpace(self):
        """Tests if the space admin can access the space index.
        """
        space_admin = self.login('foo_admin', 'foo_admin_password')
        self.assertTrue(self.isLoggedIn(space_admin))

        response = self.get(self.private_space_url)
        self.assertResponseOK(response)
        self.assertTemplateNotUsed(response, 'not_allowed.html')
        self.logout()

    def testSpaceModCanAccessThePrivateSpace(self):
        """Tests if the space mod can access the space index.
        """
        space_mod = self.login('foo_mod', 'foo_mod_password')
        self.assertTrue(self.isLoggedIn(space_mod))
        response = self.get(self.private_space_url)
        self.assertResponseOK(response)
        self.assertTemplateNotUsed(response, 'not_allowed.html')
        self.logout()

    def testSpaceUserCanAccessTheSpace(self):
        """Tests if the space user can access the space index.
        """
        space_user =  self.login('foo_user', 'foo_user_password')
        self.assertTrue(self.isLoggedIn(space_user))
        response = self.get(self.private_space_url)
        self.assertResponseOK(response)
        self.assertTemplateNotUsed(response, 'not_allowed.html')
        self.logout()

    def testOtherUsersCanNotAccessThePrivateSpace(self):
        """Test if other users who are not registered to the space can not
        access the space.
        """
        other_user = self.login('bar_admin', 'bar_admin_password')
        self.assertTrue(self.isLoggedIn(other_user))
        self.assertFalse(other_user in self.private_space.admins.all())
        response = self.get(self.private_space_url)
        self.assertResponseOK(response)
        self.assertTemplateUsed(response, 'not_allowed.html')

    def testAdminAccessToAPublicSpace(self):
        """Tests if an admin for one space can access a public space.
        """
        admin = self.login('foo_admin', 'foo_admin_password')
        self.assertTrue(self.isLoggedIn(admin))
        self.assertFalse(admin in self.public_space.admins.all())
        response = self.get(self.public_space_url)
        self.assertResponseOK(response)
        self.assertTemplateNotUsed(response, 'not_allowed.html')

    def testAnonymousUserCanAcessAPublicSpace(self):
        """Tests if an anonymous user can access a public space.
        """
        response = self.get(self.public_space_url)
        self.assertResponseOK(response)
        self.assertTemplateNotUsed(response, 'not_allowed.html')

class DeleteSpaceTest(ECDTestCase):
    """
    Tests the deletion of a space.
    """

    def setUp(self):
        self.init()

    def testGeneralUserAccess(self):
        """
        Tests if a general user is prohibited from deleting the space.
        """
        space = self.bar_space
        general_user = self.login('test_user', 'test_password')
        url = self.getURL(url_names.SPACE_DELETE, kwargs={'space_url': space.url})
        response = self.get(url)
        self.assertResponseRedirect(response)
        self.assertEqual(url, response.request['PATH_INFO'])

    def testAdminAccess(self):
        """
        Tests if a correct admin can delete a space.
        """
        space =self.bar_space
        user = self.create_super_user("other_admin", "other_password",
                                      logged_in=True)
        self.assertTrue(self.isLoggedIn(user))

        url = self.getURL(url_names.SPACE_DELETE, kwargs={'space_url': space.url})
        response = self.get(url)
        self.assertResponseOK(response)
        self.assertTemplateUsed(response, 'not_allowed.html')

        #logout the present user because the space does not belong to it
        self.logout()
        admin = self.login('bar_admin', 'bar_admin_password')
        self.assertTrue(self.isLoggedIn(admin))
        self.assertTrue(admin in space.admins.all())
        response = self.get(url)
        self.assertResponseRedirect(response)
        self.assertTemplateNotUsed(response, 'not_allowed.html')

class ListSpacesTest(ECDTestCase):
    """
    Tests the list spaces view.
    """

    def setUp(self):
        self.init()
        #We have a public space as well as a private space.
        self.private_space = self.foo_space
        self.public_space = self.bar_space
        self.url = self.getURL(url_names.SPACE_LIST)

    def testOnlyPublicSpacesAreListedForAnonymousUser(self):
        """
        Tests if only the public spaces are listed for anonymous user.
        """
        #No user is logged in currently
        response = self.get(self.url)
        self.assertResponseOK(response)
        spaces_returned = response.context[0].dicts[0]['space_list']
        self.assertEqual(len(spaces_returned), 1)
        self.assertTrue(self.public_space in spaces_returned)
        self.assertTrue(self.private_space not in spaces_returned)

    def testAllSpacesAreReturnedForALoggedInUser(self):
        """
        Tests if both the public and private spaces are returned for a logged
        in user who is registered for both the spaces.

        We make self.bar_admin to be a user for self.foo_space which is a
        private space.
        """
        self.foo_space.users.add(self.bar_admin)
        self.login('bar_admin', 'bar_admin_password')
        response = self.get(self.url)
        spaces_returned = response.context[0].dicts[0]['space_list']
        self.assertEqual(len(spaces_returned), 2)
        self.assertTrue(self.foo_space in spaces_returned)
        self.assertTrue(self.bar_space in spaces_returned)

<|endoftext|>


<commit_before>import copy
from hsgame.agents.basic_agents import DoNothingBot
from hsgame.constants import CHARACTER_CLASS
from tests.testing_agents import SpellTestingAgent
from tests.testing_utils import generate_game_for
from hsgame.cards import StonetuskBoar

__author__ = 'Daniel'
import random
import unittest
from unittest.mock import Mock, call

from hsgame.game_objects import Player, Game, Deck, Bindable, card_lookup, SecretCard

import hsgame.cards

class TestGame(unittest.TestCase):

    def setUp(self):
        random.seed(1857)

    def test_create_game(self):
        card_set1 = []
        card_set2 = []
        test_env = self

        for cardIndex in range(0, 30):
            card_set1.append(card_lookup("Stonetusk Boar"))
            card_set2.append(card_lookup("Novice Engineer"))

        deck1 = Deck(card_set1, CHARACTER_CLASS.DRUID)
        deck2 = Deck(card_set2, CHARACTER_CLASS.MAGE)
        checked_cards = []

        class MockAgent1:
            def do_card_check(self, cards):

                test_env.assertEqual(len(cards), 3)
                checked_cards.append(list(cards))
                return [False, True, True]

            def set_game(self, game):
                pass

        class MockAgent2:
            def do_card_check(self, cards):

                test_env.assertEqual(len(cards), 4)
                checked_cards.append(list(cards))
                return [False, True, True, False]

            def set_game(self, game):
                pass

        agent1 = unittest.mock.Mock(spec=MockAgent1(), wraps=MockAgent1())
        agent2 = unittest.mock.Mock(spec=MockAgent2(), wraps=MockAgent2())
        game = Game([deck1, deck2], [agent1, agent2])
        game.pre_game()
        self.assertEqual(agent1.method_calls[0][0], "set_game", "Agent not asked to select cards")
        self.assertEqual(agent2.method_calls[0][0], "set_game", "Agent not asked to select cards")

        self.assertEqual(agent1.method_calls[1][0], "do_card_check", "Agent not asked to select cards")
        self.assertEqual(agent2.method_calls[1][0], "do_card_check", "Agent not asked to select cards")

        self.assertTrue(game.players[0].deck == deck1, "Deck not assigned to player")
        self.assertTrue(game.players[1].deck == deck2, "Deck not assigned to player")

        self.assertTrue(game.players[0].agent == agent1, "Agent not stored in the hsgame")
        self.assertTrue(game.players[1].agent == agent2, "Agent not stored in the hsgame")

        self.assertListEqual(checked_cards[0][1:], game.players[0].hand[:-1], "Cards not retained after request")
        self.assertListEqual(checked_cards[1][1:2], game.players[1].hand[:-3], "Cards not retained after request")

    def test_first_turn(self):
        card_set1 = []
        card_set2 = []
        test_env = self

        for cardIndex in range(0, 30):
            card_set1.append(card_lookup("Stonetusk Boar"))
            card_set2.append(card_lookup("Novice Engineer"))

        deck1 = Deck(card_set1, CHARACTER_CLASS.DRUID)
        deck2 = Deck(card_set2, CHARACTER_CLASS.MAGE)

        agent1 = unittest.mock.Mock(spec=DoNothingBot(), wraps=DoNothingBot())
        agent2 = unittest.mock.Mock(spec=DoNothingBot(), wraps=DoNothingBot())
        game = Game([deck1, deck2], [agent1, agent2])

        game.start()

    def test_secrets(self):
        for secret_type in SecretCard.__subclasses__():
            random.seed(1857)
            secret = secret_type()
            game = generate_game_for(secret_type, StonetuskBoar, SpellTestingAgent, DoNothingBot)
            for turn in range(0, secret.mana * 2 - 2):
                game.play_single_turn()

            def assert_different():
                new_events = copy.copy(game.events)
                new_events.update(game.other_player.events)
                new_events.update(game.current_player.events)
                self.assertNotEqual(events, new_events, secret.name)

            def assert_same():
                new_events = copy.copy(game.events)
                new_events.update(game.current_player.events)
                new_events.update(game.other_player.events)
                self.assertEqual(events, new_events)

            game.current_player.bind("turn_ended", assert_different)
            game.other_player.bind("turn_ended", assert_same)

            #save the events as they are prior to the secret being played
            events = copy.copy(game.events)
            events.update(game.other_player.events)
            events.update(game.current_player.events)

            #The secret is played, but the events aren't updated until the secret is activated
            game.play_single_turn()

            self.assertEqual(1, len(game.current_player.secrets))

            #Now the events should be changed
            game.play_single_turn()

            #Now the events should be reset
            game.play_single_turn()

class TestBinding(unittest.TestCase):

    def test_bind(self):
        event = Mock()
        binder = Bindable()
        binder.bind("test", event)
        binder.trigger("test", 1, 5, 6, arg1="something", args2="whatever")
        event.assert_called_once_with(1, 5, 6, arg1="something", args2="whatever")
        binder.unbind("test", event)
        binder.trigger("test")
        event.assert_called_once_with(1, 5, 6, arg1="something", args2="whatever")

    def test_bind_once(self):
        event = Mock()
        event2 = Mock()
        binder = Bindable()
        binder.bind_once("test", event)
        binder.bind("test", event2)
        binder.trigger("test", 1, 5, 6, arg1="something", args2="whatever")
        event.assert_called_once_with(1, 5, 6, arg1="something", args2="whatever")
        event2.assert_called_once_with(1, 5, 6, arg1="something", args2="whatever")
        binder.trigger("test")
        event.assert_called_once_with(1, 5, 6, arg1="something", args2="whatever")
        self.assertEqual(event2.call_count, 2)

    def test_bind_with_different_args(self):
        event = Mock()
        event2 = Mock()
        binder = Bindable()
        binder.bind("test", event, 5)
        binder.bind("test", event2)
        binder.trigger("test")
        event.assert_called_with(5)
        event2.assert_called_with()

<commit_msg>Fix for test_secrets<commit_after>import copy
from hsgame.agents.basic_agents import DoNothingBot
from hsgame.constants import CHARACTER_CLASS
from tests.testing_agents import SpellTestingAgent
from tests.testing_utils import generate_game_for
from hsgame.cards import StonetuskBoar

__author__ = 'Daniel'
import random
import unittest
from unittest.mock import Mock, call

from hsgame.game_objects import Player, Game, Deck, Bindable, card_lookup, SecretCard

import hsgame.cards

class TestGame(unittest.TestCase):

    def setUp(self):
        random.seed(1857)

    def test_create_game(self):
        card_set1 = []
        card_set2 = []
        test_env = self

        for cardIndex in range(0, 30):
            card_set1.append(card_lookup("Stonetusk Boar"))
            card_set2.append(card_lookup("Novice Engineer"))

        deck1 = Deck(card_set1, CHARACTER_CLASS.DRUID)
        deck2 = Deck(card_set2, CHARACTER_CLASS.MAGE)
        checked_cards = []

        class MockAgent1:
            def do_card_check(self, cards):

                test_env.assertEqual(len(cards), 3)
                checked_cards.append(list(cards))
                return [False, True, True]

            def set_game(self, game):
                pass

        class MockAgent2:
            def do_card_check(self, cards):

                test_env.assertEqual(len(cards), 4)
                checked_cards.append(list(cards))
                return [False, True, True, False]

            def set_game(self, game):
                pass

        agent1 = unittest.mock.Mock(spec=MockAgent1(), wraps=MockAgent1())
        agent2 = unittest.mock.Mock(spec=MockAgent2(), wraps=MockAgent2())
        game = Game([deck1, deck2], [agent1, agent2])
        game.pre_game()
        self.assertEqual(agent1.method_calls[0][0], "set_game", "Agent not asked to select cards")
        self.assertEqual(agent2.method_calls[0][0], "set_game", "Agent not asked to select cards")

        self.assertEqual(agent1.method_calls[1][0], "do_card_check", "Agent not asked to select cards")
        self.assertEqual(agent2.method_calls[1][0], "do_card_check", "Agent not asked to select cards")

        self.assertTrue(game.players[0].deck == deck1, "Deck not assigned to player")
        self.assertTrue(game.players[1].deck == deck2, "Deck not assigned to player")

        self.assertTrue(game.players[0].agent == agent1, "Agent not stored in the hsgame")
        self.assertTrue(game.players[1].agent == agent2, "Agent not stored in the hsgame")

        self.assertListEqual(checked_cards[0][1:], game.players[0].hand[:-1], "Cards not retained after request")
        self.assertListEqual(checked_cards[1][1:2], game.players[1].hand[:-3], "Cards not retained after request")

    def test_first_turn(self):
        card_set1 = []
        card_set2 = []
        test_env = self

        for cardIndex in range(0, 30):
            card_set1.append(card_lookup("Stonetusk Boar"))
            card_set2.append(card_lookup("Novice Engineer"))

        deck1 = Deck(card_set1, CHARACTER_CLASS.DRUID)
        deck2 = Deck(card_set2, CHARACTER_CLASS.MAGE)

        agent1 = unittest.mock.Mock(spec=DoNothingBot(), wraps=DoNothingBot())
        agent2 = unittest.mock.Mock(spec=DoNothingBot(), wraps=DoNothingBot())
        game = Game([deck1, deck2], [agent1, agent2])

        game.start()

    def test_secrets(self):
        for secret_type in SecretCard.__subclasses__():
            random.seed(1857)
            secret = secret_type()
            game = generate_game_for(secret_type, StonetuskBoar, SpellTestingAgent, DoNothingBot)
            for turn in range(0, secret.mana * 2):
                game.play_single_turn()

            def assert_different():
                new_events = copy.copy(game.events)
                new_events.update(game.other_player.events)
                new_events.update(game.current_player.events)
                self.assertNotEqual(events, new_events, secret.name)

            def assert_same():
                new_events = copy.copy(game.events)
                new_events.update(game.current_player.events)
                new_events.update(game.other_player.events)
                self.assertEqual(events, new_events)

            game.current_player.bind("turn_ended", assert_different)
            game.other_player.bind("turn_ended", assert_same)

            #save the events as they are prior to the secret being played
            events = copy.copy(game.events)
            events.update(game.other_player.events)
            events.update(game.current_player.events)

            #The secret is played, but the events aren't updated until the secret is activated
            game.play_single_turn()

            self.assertEqual(1, len(game.current_player.secrets))

            #Now the events should be changed
            game.play_single_turn()

            #Now the events should be reset
            game.play_single_turn()

class TestBinding(unittest.TestCase):

    def test_bind(self):
        event = Mock()
        binder = Bindable()
        binder.bind("test", event)
        binder.trigger("test", 1, 5, 6, arg1="something", args2="whatever")
        event.assert_called_once_with(1, 5, 6, arg1="something", args2="whatever")
        binder.unbind("test", event)
        binder.trigger("test")
        event.assert_called_once_with(1, 5, 6, arg1="something", args2="whatever")

    def test_bind_once(self):
        event = Mock()
        event2 = Mock()
        binder = Bindable()
        binder.bind_once("test", event)
        binder.bind("test", event2)
        binder.trigger("test", 1, 5, 6, arg1="something", args2="whatever")
        event.assert_called_once_with(1, 5, 6, arg1="something", args2="whatever")
        event2.assert_called_once_with(1, 5, 6, arg1="something", args2="whatever")
        binder.trigger("test")
        event.assert_called_once_with(1, 5, 6, arg1="something", args2="whatever")
        self.assertEqual(event2.call_count, 2)

    def test_bind_with_different_args(self):
        event = Mock()
        event2 = Mock()
        binder = Bindable()
        binder.bind("test", event, 5)
        binder.bind("test", event2)
        binder.trigger("test")
        event.assert_called_with(5)
        event2.assert_called_with()

<|endoftext|>


<commit_before>#
# Created as part of the StratusLab project (http://stratuslab.eu),
# co-funded by the European Commission under the Grant Agreement
# INFSO-RI-261552."
#
# Copyright (c) 2012, Centre National de la Recherche Scientifique
#
# 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.
#
import os
import stat

import stratuslab.system.SystemFactory as SystemFactory
from stratuslab.installator.Installator import Installator
from stratuslab import Util

class OpenLDAP(Installator):

    def __init__(self, configHolder):
        configHolder.assign(self)
        self.system = SystemFactory.getSystem(self.frontendSystem, configHolder)

        self._serviceName = 'slapd'
        self._packages = ['stratuslab-openldap-support']

        self._sharepath = '/usr/share/stratuslab/registration-openldap'

        self._sysconfigLdap = '/etc/sysconfig/ldap'
        self._sysconfigLdapTemplate = '%s/sysconfig/ldap' % self._sharepath

        self._testCertCmd = '%s/scripts/generate-self-signed-certificate.sh' % self._sharepath
        self._certConfigLdif = '%s/ldif/certificates-config.ldif' % self._sharepath

        self._ldapClientConfig = '/etc/openldap/ldap.conf'

        self._openLdapConfig = '/etc/openldap/slapd.d/cn=config/olcDatabase={0}config.ldif'
        self._accessValue  = 'olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * none'

        self._databaseTemplate = '%s/ldif/cloud-db-defn.ldif' % self._sharepath
        self._completeDatabaseTemplate = 'cloud-db-defn.ldif'

        self._cloudDatabaseSkeleton = '%s/ldif/cloud-data.ldif' % self._sharepath

        self._openLdapAdminDn = 'cn=admin,o=cloud'

        self._nodename = 'onehost-5.lal.in2p3.fr'

    def _installFrontend(self):
        self._installPackages()

    def _setupFrontend(self):
        self._configure()

    def _startServicesFrontend(self):
        self._restartService()

    def _installPackages(self):
        Util.printStep('Installing packages')
        self.system.installPackages(self._packages)

    def _configure(self):
        Util.printStep('Configuring OpenLDAP server')

        Util.printStep('Updating sysconfig')
        Util.filePutContent(self._sysconfigLdap,
                            Util.fileGetContent(self._sysconfigLdapTemplate))
        Util.appendOrReplaceInFile(self._sysconfigLdap, 'SLAPD_LDAP=', 'SLAPD_LDAP=yes')

        Util.printStep('Setting root account access')
        Util.appendOrReplaceInFile(self._openLdapConfig, 'olcAccess:', self._accessValue)

        Util.printStep('(Re-)starting slapd')
        cmd = 'service %s restart' % self._serviceName
        Util.execute(cmd.split(' '))

        Util.printStep('Generating test certificate and moving into place')
        Util.execute(self._testCertCmd.split(' '))

        Util.execute('mv -f cacrt.jks /etc/openldap/cacerts/cacrt.jks'.split(' '))
        Util.execute('mv -f cacrt.pem /etc/openldap/cacerts/cacrt.pem'.split(' '))
        Util.execute('mv -f serverkey.pem /etc/openldap/serverkey.pem'.split(' '))
        Util.execute('mv -f servercrt.pem /etc/openldap/servercrt.pem'.split(' '))

        os.chmod('/etc/openldap/serverkey.pem', stat.S_IRUSR | stat.S_IWUSR)
        Util.execute('chown ldap:ldap /etc/openldap/serverkey.pem'.split(' '))

        Util.printStep('Updating server config. for generated certs')
        cmd = "ldapmodify -Y EXTERNAL -H ldapi:/// -f %s" % self._certConfigLdif
        Util.execute(cmd.split(' '))

        Util.printStep('Updating client config. for generated certs')
        Util.appendOrReplaceInFile(self._ldapClientConfig,
                                   'TLS_CACERT',
                                   'TLS_CACERT /etc/openldap/cacerts/cacrt.pem')

        Util.printStep('Creating o=cloud database')
        Util.filePutContent(self._completeDatabaseTemplate,
                            Util.fileGetContent(self._databaseTemplate) % self.__dict__)

        cmd = "ldapadd -Y EXTERNAL -H ldapi:/// -f %s" % self._completeDatabaseTemplate
        Util.execute(cmd.split(' '))

        Util.printStep('Adding cloud database entries')
        cmd = "ldapadd -x -H ldaps://%s -D %s -w %s -f %s" % (self._nodename, self._openLdapAdminDn, self.openldapPassword, self._cloudDatabaseSkeleton)
        Util.execute(cmd.split(' '))

    def _restartService(self):
        Util.printStep("Adding %s to chkconfig and restarting" % self._serviceName)
        cmd = 'chkconfig --add %s' % self._serviceName
        Util.execute(cmd.split(' '))
        cmd = 'service %s restart' % self._serviceName
        Util.execute(cmd.split(' '))
<commit_msg>simply overwrite ldap config with the template config.file provided by StratusLab instead of fiddling with copying of the file content<commit_after>#
# Created as part of the StratusLab project (http://stratuslab.eu),
# co-funded by the European Commission under the Grant Agreement
# INFSO-RI-261552."
#
# Copyright (c) 2012, Centre National de la Recherche Scientifique
#
# 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.
#
import os
import shutil
import stat

import stratuslab.system.SystemFactory as SystemFactory
from stratuslab.installator.Installator import Installator
from stratuslab import Util

class OpenLDAP(Installator):

    def __init__(self, configHolder):
        configHolder.assign(self)
        self.system = SystemFactory.getSystem(self.frontendSystem, configHolder)

        self._serviceName = 'slapd'
        self._packages = ['stratuslab-openldap-support']

        self._sharepath = '/usr/share/stratuslab/registration-openldap'

        self._sysconfigLdap = '/etc/sysconfig/ldap'
        self._sysconfigLdapTemplate = '%s/sysconfig/ldap' % self._sharepath

        self._testCertCmd = '%s/scripts/generate-self-signed-certificate.sh' % self._sharepath
        self._certConfigLdif = '%s/ldif/certificates-config.ldif' % self._sharepath

        self._ldapClientConfig = '/etc/openldap/ldap.conf'

        self._openLdapConfig = '/etc/openldap/slapd.d/cn=config/olcDatabase={0}config.ldif'
        self._accessValue  = 'olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * none'

        self._databaseTemplate = '%s/ldif/cloud-db-defn.ldif' % self._sharepath
        self._completeDatabaseTemplate = 'cloud-db-defn.ldif'

        self._cloudDatabaseSkeleton = '%s/ldif/cloud-data.ldif' % self._sharepath

        self._openLdapAdminDn = 'cn=admin,o=cloud'

        self._nodename = 'onehost-5.lal.in2p3.fr'

    def _installFrontend(self):
        self._installPackages()

    def _setupFrontend(self):
        self._configure()

    def _startServicesFrontend(self):
        self._restartService()

    def _installPackages(self):
        Util.printStep('Installing packages')
        self.system.installPackages(self._packages)

    def _configure(self):
        Util.printStep('Configuring OpenLDAP server')

        Util.printStep('Updating sysconfig')
        shutil.copyfile(self._sysconfigLdapTemplate, self._sysconfigLdap)
        Util.appendOrReplaceInFile(self._sysconfigLdap, 'SLAPD_LDAP=', 'SLAPD_LDAP=yes')

        Util.printStep('Setting root account access')
        Util.appendOrReplaceInFile(self._openLdapConfig, 'olcAccess:', self._accessValue)

        Util.printStep('(Re-)starting slapd')
        cmd = 'service %s restart' % self._serviceName
        Util.execute(cmd.split(' '))

        Util.printStep('Generating test certificate and moving into place')
        Util.execute(self._testCertCmd.split(' '))

        Util.execute('mv -f cacrt.jks /etc/openldap/cacerts/cacrt.jks'.split(' '))
        Util.execute('mv -f cacrt.pem /etc/openldap/cacerts/cacrt.pem'.split(' '))
        Util.execute('mv -f serverkey.pem /etc/openldap/serverkey.pem'.split(' '))
        Util.execute('mv -f servercrt.pem /etc/openldap/servercrt.pem'.split(' '))

        os.chmod('/etc/openldap/serverkey.pem', stat.S_IRUSR | stat.S_IWUSR)
        Util.execute('chown ldap:ldap /etc/openldap/serverkey.pem'.split(' '))

        Util.printStep('Updating server config. for generated certs')
        cmd = "ldapmodify -Y EXTERNAL -H ldapi:/// -f %s" % self._certConfigLdif
        Util.execute(cmd.split(' '))

        Util.printStep('Updating client config. for generated certs')
        Util.appendOrReplaceInFile(self._ldapClientConfig,
                                   'TLS_CACERT',
                                   'TLS_CACERT /etc/openldap/cacerts/cacrt.pem')

        Util.printStep('Creating o=cloud database')
        Util.filePutContent(self._completeDatabaseTemplate,
                            Util.fileGetContent(self._databaseTemplate) % self.__dict__)

        cmd = "ldapadd -Y EXTERNAL -H ldapi:/// -f %s" % self._completeDatabaseTemplate
        Util.execute(cmd.split(' '))

        Util.printStep('Adding cloud database entries')
        cmd = "ldapadd -x -H ldaps://%s -D %s -w %s -f %s" % (self._nodename, self._openLdapAdminDn, self.openldapPassword, self._cloudDatabaseSkeleton)
        Util.execute(cmd.split(' '))

    def _restartService(self):
        Util.printStep("Adding %s to chkconfig and restarting" % self._serviceName)
        cmd = 'chkconfig --add %s' % self._serviceName
        Util.execute(cmd.split(' '))
        cmd = 'service %s restart' % self._serviceName
        Util.execute(cmd.split(' '))
<|endoftext|>