<commit_before># vim: set encoding=utf-8
import unittest

from selenium.webdriver.support.ui import WebDriverWait

from regulations.uitests.base_test import BaseTest
from regulations.uitests import utils

class DefinitionTest(BaseTest, unittest.TestCase):

    job_name = 'Definitions test'

    def test_definition(self):
        self.driver.set_window_size(1024, 600)
        self.driver.get(self.test_url + '/1005-1/2012-12121')
        html = self.driver.find_element_by_tag_name('html')
        WebDriverWait(self.driver, 30).until(
            lambda driver: 'selenium-start' in html.get_attribute('class'))
        definition_link = self.driver.find_element_by_xpath(
            '//*[@id="1005-1-a"]//a')
        # term link should have correct data attr
        self.assertIn(
            '1005-2-a-1', definition_link.get_attribute('data-definition'))

        definition_link.click()

        # term link should get active class
        self.assertIn('active', definition_link.get_attribute('class'))

        definition = self.driver.find_element_by_xpath('//*[@id="1005-2-a-1"]')
        definition_close_button = self.driver.find_element_by_xpath(
            '//*[@id="1005-2-a-1"]/div[1]/h4/a')

        # definition should appear in sidebar
        self.assertGreater(len(definition.text), 20)
        definition_term = self.driver.find_element_by_xpath(
            '//*[@id="1005-2-a-1"]/div[3]/p/dfn')
        self.assertIn(u'\u201cvoided tosser\u201d', definition_term.text)

        definition_close_button.click()
        # definition should close
        self.assertFalse('active' in definition_link.get_attribute('class'))

        definition_link.click()

        # continue link should load full def
        definition_cont_link = self.driver.find_element_by_xpath(
            '//*[@id="1005-2-a-1"]/div[3]/a[1]')
        definition_cont_link.click()
        WebDriverWait(self.driver, 30).until(
            lambda driver: driver.find_element_by_xpath('//*[@id="1005-2"]'))

        # test definition scope notifications
        toc_toggle = self.driver.find_element_by_css_selector('#panel-link')
        toc_toggle.click()

        toc_1005_3 = self.driver.find_element_by_xpath(
            '//*[@id="toc"]/ol/li[3]/a')
        toc_1005_3.click()

        # close toc
        toc_toggle.click()

        # load 1005.3, open definition
        new_definition_link = self.driver.find_element_by_xpath(
            '//*[@id="1005-3-a"]//a[1]')
        self.driver.execute_script('window.scrollTo(0, 0);')
        new_definition_link.click()
        self.driver.find_element_by_xpath('//*[@id="1005-2-b-1"]')

        # navigate back to 1005.1
        toc_toggle.click()
        self.driver.find_element_by_xpath('//*[@id="toc"]/ol/li[1]/a').click()

        # make sure that the scope notice displays
        self.driver.find_element_by_xpath('//*[@id="1005-2-b-1"]/div[2]/div')

        # go to 1005-1-a
        toc_toggle.click()
        utils.scroll_to(self.driver, '#1005-1-a')

        definition_update_link = self.driver.find_element_by_css_selector(
            '.update-definition')
        definition_text = self.driver.find_element_by_css_selector(
            '.definition-text')

        # make sure text is grayed out
        self.assertIn('inactive', definition_text.get_attribute('class'))

        # load in scope definition
        definition_update_link.click()
        WebDriverWait(self.driver, 10).until(
            lambda driver: driver.find_element_by_xpath(
                '//*[@id="1005-2-a-1"]'))
<commit_msg>Account for moved close button in definitions<commit_after># vim: set encoding=utf-8
import unittest

from selenium.webdriver.support.ui import WebDriverWait

from regulations.uitests.base_test import BaseTest
from regulations.uitests import utils

class DefinitionTest(BaseTest, unittest.TestCase):

    job_name = 'Definitions test'

    def test_definition(self):
        self.driver.set_window_size(1024, 600)
        self.driver.get(self.test_url + '/1005-1/2012-12121')
        html = self.driver.find_element_by_tag_name('html')
        WebDriverWait(self.driver, 30).until(
            lambda driver: 'selenium-start' in html.get_attribute('class'))
        definition_link = self.driver.find_element_by_xpath(
            '//*[@id="1005-1-a"]//a')
        # term link should have correct data attr
        self.assertIn(
            '1005-2-a-1', definition_link.get_attribute('data-definition'))

        definition_link.click()

        # term link should get active class
        self.assertIn('active', definition_link.get_attribute('class'))

        definition = self.driver.find_element_by_id('1005-2-a-1')
        definition_close_button = definition.find_element_by_class_name(
            'close-button')

        # definition should appear in sidebar
        self.assertGreater(len(definition.text), 20)
        definition_term = definition.find_element_by_class_name('defined-term')
        self.assertIn(u'\u201cvoided tosser\u201d', definition_term.text)

        definition_close_button.click()
        # definition should close
        self.assertFalse('active' in definition_link.get_attribute('class'))

        definition_link.click()

        # continue link should load full def
        definition = self.driver.find_element_by_id('1005-2-a-1')
        definition_cont_link = definition.find_element_by_class_name(
            'full-def')
        definition_cont_link.click()
        WebDriverWait(self.driver, 30).until(
            lambda driver: driver.find_element_by_xpath('//*[@id="1005-2"]'))

        # test definition scope notifications
        toc_toggle = self.driver.find_element_by_css_selector('#panel-link')
        toc_toggle.click()

        toc_1005_3 = self.driver.find_element_by_xpath(
            '//*[@id="toc"]/ol/li[3]/a')
        toc_1005_3.click()

        # close toc
        toc_toggle.click()

        # load 1005.3, open definition
        new_definition_link = self.driver.find_element_by_xpath(
            '//*[@id="1005-3-a"]//a[1]')
        self.driver.execute_script('window.scrollTo(0, 0);')
        new_definition_link.click()
        self.driver.find_element_by_xpath('//*[@id="1005-2-b-1"]')

        # navigate back to 1005.1
        toc_toggle.click()
        self.driver.find_element_by_xpath('//*[@id="toc"]/ol/li[1]/a').click()

        # make sure that the scope notice displays
        definition = self.driver.find_element_by_id('1005-2-b-1')
        definition.find_element_by_class_name('definition-warning')

        # go to 1005-1-a
        toc_toggle.click()
        utils.scroll_to(self.driver, '#1005-1-a')

        definition_update_link = self.driver.find_element_by_class_name(
            'update-definition')
        definition_text = self.driver.find_element_by_class_name(
            'definition-text')

        # make sure text is grayed out
        self.assertIn('inactive', definition_text.get_attribute('class'))

        # load in scope definition
        definition_update_link.click()
        WebDriverWait(self.driver, 10).until(
            lambda driver: driver.find_element_by_xpath(
                '//*[@id="1005-2-a-1"]'))
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Andy Sayler
# Summer 2014
# Univerity of Colorado

import copy
import unittest

import structs
import test_common

class TypesTestCase(test_common.CogsTestCase):

    def setUp(self):
        super(TypesTestCase, self).setUp()

    def tearDown(self):
        super(TypesTestCase, self).tearDown()

class ServerTestCase(TypesTestCase):

    def setUp(self):
        super(ServerTestCase, self).setUp()
        self.s = structs.Server(db=self.db)

    def tearDown(self):
        del(self.s)
        super(ServerTestCase, self).tearDown()

    def test_assignments(self):

        assignments_in = set([])

        # List Assignments (Empty DB)
        assignments_out = self.s.list_assignments()
        self.assertEqual(assignments_in, assignments_out)

        # Generate 10 Assignments
        for i in range(10):
            d = copy.deepcopy(test_common.ASSIGNMENT_TESTDICT)
            for k in d:
                d[k] = "{:s}_test_{:02d}".format(d[k], i)
            assignments_in.add(str(self.s.create_assignment(d).uuid))

        # List Assignments
        assignments_out = self.s.list_assignments()
        self.assertEqual(assignments_in, assignments_out)

    def test_users(self):

        users_in = set([])

        # List Users (Empty DB)
        users_out = self.s.list_users()
        self.assertEqual(users_in, users_out)

        # Generate 10 Users
        for i in range(10):
            d = copy.deepcopy(test_common.USER_TESTDICT)
            for k in d:
                d[k] = "{:s}_test_{:02d}".format(d[k], i)
            users_in.add(str(self.s.create_user(d).uuid))

        # List Users
        users_out = self.s.list_users()
        self.assertEqual(users_in, users_out)

class AssignmentTestCase(TypesTestCase):

    def setUp(self):
        super(AssignmentTestCase, self).setUp()
        self.srv = structs.Server(self.db)

    def tearDown(self):
        super(AssignmentTestCase, self).tearDown()

    def test_create_assignment(self):

        # Test Empty Dict
        d = {}
        self.assertRaises(KeyError, self.srv.create_assignment, d)

        # Test Bad Dict
        d = {'test': "test"}
        self.assertRaises(KeyError, self.srv.create_assignment, d)

        # Test Sub Dict
        d = copy.deepcopy(test_common.ASSIGNMENT_TESTDICT)
        d.pop(d.keys()[0])
        self.assertRaises(KeyError, self.srv.create_assignment, d)

        # Test Super Dict
        d = copy.deepcopy(test_common.ASSIGNMENT_TESTDICT)
        d['test'] = "test"
        self.assertRaises(KeyError, self.srv.create_assignment, d)

        # Test Valid
        d = copy.deepcopy(test_common.ASSIGNMENT_TESTDICT)
        asn = self.srv.create_assignment(d)
        self.assertSubset(d, asn.get_dict())

    def test_get_assignment(self):

        # Test Invalid UUID
        self.assertRaises(structs.ObjectDNE,
                          self.srv.get_assignment,
                          'eb424026-6f54-4ef8-a4d0-bb658a1fc6cf')

        # Test Valid UUID
        d = copy.deepcopy(test_common.ASSIGNMENT_TESTDICT)
        asn1 = self.srv.create_assignment(d)
        asn1_uuid = asn1.uuid
        asn2 = self.srv.get_assignment(asn1_uuid)
        self.assertEqual(asn1, asn2)

class TestTestCase(TypesTestCase):

    def setUp(self):
        super(TestTestCase, self).setUp()
        self.srv = structs.Server(self.db)
        self.asn = self.srv.create_assignment(test_common.ASSIGNMENT_TESTDICT)

    def tearDown(self):
        super(TestTestCase, self).tearDown()

    def test_create_test(self):

        # Test Empty Dict
        d = {}
        self.assertRaises(KeyError, self.asn.create_test, d)

        # Test Bad Dict
        d = {'test': "test"}
        self.assertRaises(KeyError, self.asn.create_test, d)

        # Test Sub Dict
        d = copy.deepcopy(test_common.TEST_TESTDICT)
        d.pop(d.keys()[0])
        self.assertRaises(KeyError, self.asn.create_test, d)

        # Test Super Dict
        d = copy.deepcopy(test_common.TEST_TESTDICT)
        d['test'] = "test"
        self.assertRaises(KeyError, self.asn.create_test, d)

        # Test Valid
        d = copy.deepcopy(test_common.TEST_TESTDICT)
        tst = self.asn.create_test(d)
        self.assertSubset(d, tst.get_dict())

    def test_get_test(self):

        # Test Invalid UUID
        self.assertRaises(structs.ObjectDNE,
                          self.asn.get_test,
                          'eb424026-6f54-4ef8-a4d0-bb658a1fc6cf')

        # Test Valid UUID
        d = copy.deepcopy(test_common.TEST_TESTDICT)
        tst1 = self.asn.create_test(d)
        tst1_uuid = tst1.uuid
        tst2 = self.asn.get_test(tst1_uuid)
        self.assertEqual(tst1, tst2)

# Main
if __name__ == '__main__':
    unittest.main()
<commit_msg>Added user tests and made generic test helpers<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Andy Sayler
# Summer 2014
# Univerity of Colorado

import copy
import unittest

import structs
import test_common

class TypesTestCase(test_common.CogsTestCase):

    def setUp(self):
        super(TypesTestCase, self).setUp()

    def tearDown(self):
        super(TypesTestCase, self).tearDown()

    def subHashDirectHelper(self, hash_create, hash_list, input_dict):

        objects_in = set([])

        # List Objects (Empty DB)
        objects_out = hash_list()
        self.assertEqual(objects_in, objects_out)

        # Generate 10 Objects
        for i in range(10):
            d = copy.copy(input_dict)
            for k in d:
                d[k] = "{:s}_test_{:02d}".format(d[k], i)
            objects_in.add(str(hash_create(d).obj_key))

        # List Objects
        objects_out = hash_list()
        self.assertEqual(objects_in, objects_out)

    def hashCreateHelper(self, hash_create, input_dict):

        # Test Empty Dict
        d = {}
        self.assertRaises(KeyError, hash_create, d)

        # Test Bad Dict
        d = {'badkey': "test"}
        self.assertRaises(KeyError, hash_create, d)

        # Test Sub Dict
        d = copy.copy(input_dict)
        d.pop(d.keys()[0])
        self.assertRaises(KeyError, hash_create, d)

        # Test Super Dict
        d = copy.copy(input_dict)
        d['badkey'] = "test"
        self.assertRaises(KeyError, hash_create, d)

    def hashGetHelper(self, hash_create, hash_get, input_dict):

        # Test Invalid UUID
        self.assertRaises(structs.ObjectDNE,
                          hash_get,
                          'eb424026-6f54-4ef8-a4d0-bb658a1fc6cf')

        # Test Valid UUID
        d = copy.copy(input_dict)
        obj1 = hash_create(d)
        obj1_key = obj1.obj_key
        obj2 = hash_get(obj1_key)
        self.assertEqual(obj1, obj2)
        self.assertEqual(obj1.get_dict(), obj2.get_dict())

class ServerTestCase(TypesTestCase):

    def setUp(self):
        super(ServerTestCase, self).setUp()
        self.srv = structs.Server(db=self.db)

    def tearDown(self):
        del(self.srv)
        super(ServerTestCase, self).tearDown()

    def test_assignments(self):
        self.subHashDirectHelper(self.srv.create_assignment,
                                 self.srv.list_assignments,
                                 test_common.ASSIGNMENT_TESTDICT)

    def test_users(self):
        self.subHashDirectHelper(self.srv.create_user,
                                 self.srv.list_users,
                                 test_common.USER_TESTDICT)

class UserTestCase(TypesTestCase):

    def setUp(self):
        super(UserTestCase, self).setUp()
        self.srv = structs.Server(self.db)

    def tearDown(self):
        super(UserTestCase, self).tearDown()

    def test_create_user(self):
        self.hashCreateHelper(self.srv.create_user,
                              test_common.USER_TESTDICT)

    def test_get_user(self):
        self.hashGetHelper(self.srv.create_user,
                           self.srv.get_user,
                           test_common.USER_TESTDICT)

class AssignmentTestCase(TypesTestCase):

    def setUp(self):
        super(AssignmentTestCase, self).setUp()
        self.srv = structs.Server(self.db)

    def tearDown(self):
        super(AssignmentTestCase, self).tearDown()

    def test_create_assignment(self):
        self.hashCreateHelper(self.srv.create_assignment,
                              test_common.ASSIGNMENT_TESTDICT)

    def test_get_assignment(self):
        self.hashGetHelper(self.srv.create_assignment,
                           self.srv.get_assignment,
                           test_common.ASSIGNMENT_TESTDICT)

class TestTestCase(TypesTestCase):

    def setUp(self):
        super(TestTestCase, self).setUp()
        self.srv = structs.Server(self.db)
        self.asn = self.srv.create_assignment(test_common.ASSIGNMENT_TESTDICT)

    def tearDown(self):
        super(TestTestCase, self).tearDown()

    def test_create_test(self):
        self.hashCreateHelper(self.asn.create_test,
                              test_common.TEST_TESTDICT)

    def test_get_test(self):
        self.hashGetHelper(self.asn.create_test,
                           self.asn.get_test,
                           test_common.TEST_TESTDICT)

# Main
if __name__ == '__main__':
    unittest.main()
<|endoftext|>


<commit_before>#!/usr/bin/env python
# Copyright (c) 2011 OpenStack, LLC.
#
# 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.

# This is designed to be called by a gerrit hook.  It searched new
# patchsets for strings like "bug FOO" and updates corresponding Launchpad
# bugs status.

from launchpadlib.launchpad import Launchpad
from launchpadlib.uris import LPNET_SERVICE_ROOT
import os
import argparse
import re
import subprocess

BASE_DIR = '/home/gerrit2/review_site'
GERRIT_CACHE_DIR = os.path.expanduser(os.environ.get('GERRIT_CACHE_DIR',
                                '~/.launchpadlib/cache'))
GERRIT_CREDENTIALS = os.path.expanduser(os.environ.get('GERRIT_CREDENTIALS',
                                '~/.launchpadlib/creds'))

def add_change_proposed_message(bugtask, change_url, project, branch):
    subject = 'Fix proposed to %s (%s)' % (short_project(project), branch)
    body = 'Fix proposed to branch: %s\nReview: %s' % (branch, change_url)
    bugtask.bug.newMessage(subject=subject, content=body)

def add_change_merged_message(bugtask, change_url, project, commit,
                              submitter, branch, git_log):
    subject = 'Fix merged to %s (%s)' % (short_project(project), branch)
    git_url = 'http://github.com/%s/commit/%s' % (project, commit)
    body = '''Reviewed:  %s
Committed: %s
Submitter: %s
Branch:    %s\n''' % (change_url, git_url, submitter, branch)
    body = body + '\n' + git_log
    bugtask.bug.newMessage(subject=subject, content=body)

def set_in_progress(bugtask, launchpad, uploader, change_url):
    """Set bug In progress with assignee being the uploader"""

    # Retrieve uploader from Launchpad. Use email as search key if
    # provided, and only set if there is a clear match.
    try:
        searchkey = uploader[uploader.rindex("(") + 1:-1]
    except ValueError:
        searchkey = uploader
    persons = launchpad.people.findPerson(text=searchkey)
    if len(persons) == 1:
        bugtask.assignee = persons[0]

    bugtask.status = "In Progress"
    bugtask.lp_save()

def set_fix_committed(bugtask):
    """Set bug fix committed"""

    bugtask.status = "Fix Committed"
    bugtask.lp_save()

def release_fixcommitted(bugtask):
    """Set bug FixReleased if it was FixCommitted"""

    if bugtask.status == u'Fix Committed':
        bugtask.status = "Fix Released"
        bugtask.lp_save()

def tag_in_branchname(bugtask, branch):
    """Tag bug with in-branch-name tag (if name is appropriate)"""

    lp_bug = bugtask.bug
    branch_name = branch.replace('/', '-')
    if branch_name.replace('-', '').isalnum():
        lp_bug.tags = lp_bug.tags + ["in-%s" % branch_name]
        lp_bug.tags.append("in-%s" % branch_name)
        lp_bug.lp_save()

def short_project(full_project_name):
    """Return the project part of the git repository name"""
    return full_project_name.split('/')[-1]

def git2lp(full_project_name):
    """Convert Git repo name to Launchpad project"""
    project_map = {
        'openstack/python-glanceclient': 'glance',
        'openstack/python-keystoneclient': 'keystone',
        'openstack/python-melangeclient': 'melange',
        'openstack/python-novaclient': 'nova',
        'openstack/python-quantumclient': 'quantum',
        'openstack/openstack-ci-puppet': 'openstack-ci',
        'openstack-ci/devstack-gate': 'openstack-ci',
        }
    return project_map.get(full_project_name, short_project(full_project_name))

def process_bugtask(launchpad, bugtask, git_log, args):
    """Apply changes to bugtask, based on hook / branch..."""

    if args.hook == "change-merged":
        if args.branch == 'master':
            set_fix_committed(bugtask)
        elif args.branch == 'milestone-proposed':
            release_fixcommitted(bugtask)
        else:
            tag_in_branchname(bugtask, args.branch)
        add_change_merged_message(bugtask, args.change_url, args.project,
                                  args.commit, args.submitter, args.branch,
                                  git_log)

    if args.hook == "patchset-created":
        if args.branch == 'master':
            set_in_progress(bugtask, launchpad, args.uploader, args.change_url)
        if args.patchset == '1':
            add_change_proposed_message(bugtask, args.change_url,
                                        args.project, args.branch)

def find_bugs(launchpad, git_log, args):
    """Find bugs referenced in the git log and return related bugtasks"""

    bug_regexp = r'([Bb]ug|[Ll][Pp])[\s#:]*(\d+)'
    tokens = re.split(bug_regexp, git_log)

    # Extract unique bug tasks
    bugtasks = {}
    for token in tokens:
        if re.match('^\d+$', token) and (token not in bugtasks):
            try:
                lp_bug = launchpad.bugs[token]
                for lp_task in lp_bug.bug_tasks:
                    if lp_task.bug_target_name == git2lp(args.project):
                        bugtasks[token] = lp_task
                        break
            except KeyError:
                # Unknown bug
                pass

    return bugtasks.values()

def extract_git_log(args):
    """Extract git log of all merged commits"""
    cmd = ['git',
           '--git-dir=' + BASE_DIR + '/git/' + args.project + '.git',
           'log', '--no-merges', args.commit + '^1..' + args.commit]
    return subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0]

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('hook')
    #common
    parser.add_argument('--change', default=None)
    parser.add_argument('--change-url', default=None)
    parser.add_argument('--project', default=None)
    parser.add_argument('--branch', default=None)
    parser.add_argument('--commit', default=None)
    #change-merged
    parser.add_argument('--submitter', default=None)
    #patchset-created
    parser.add_argument('--uploader', default=None)
    parser.add_argument('--patchset', default=None)

    args = parser.parse_args()

    # Connect to Launchpad
    launchpad = Launchpad.login_with('Gerrit User Sync', LPNET_SERVICE_ROOT,
                                     GERRIT_CACHE_DIR,
                                     credentials_file=GERRIT_CREDENTIALS,
                                     version='devel')

    # Get git log
    git_log = extract_git_log(args)

    # Process bugtasks found in git log
    for bugtask in find_bugs(launchpad, git_log, args):
        process_bugtask(launchpad, bugtask, git_log, args)

if __name__ == '__main__':
    main()
<commit_msg>Add python-cinderclient support.<commit_after>#!/usr/bin/env python
# Copyright (c) 2011 OpenStack, LLC.
#
# 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.

# This is designed to be called by a gerrit hook.  It searched new
# patchsets for strings like "bug FOO" and updates corresponding Launchpad
# bugs status.

from launchpadlib.launchpad import Launchpad
from launchpadlib.uris import LPNET_SERVICE_ROOT
import os
import argparse
import re
import subprocess

BASE_DIR = '/home/gerrit2/review_site'
GERRIT_CACHE_DIR = os.path.expanduser(os.environ.get('GERRIT_CACHE_DIR',
                                '~/.launchpadlib/cache'))
GERRIT_CREDENTIALS = os.path.expanduser(os.environ.get('GERRIT_CREDENTIALS',
                                '~/.launchpadlib/creds'))

def add_change_proposed_message(bugtask, change_url, project, branch):
    subject = 'Fix proposed to %s (%s)' % (short_project(project), branch)
    body = 'Fix proposed to branch: %s\nReview: %s' % (branch, change_url)
    bugtask.bug.newMessage(subject=subject, content=body)

def add_change_merged_message(bugtask, change_url, project, commit,
                              submitter, branch, git_log):
    subject = 'Fix merged to %s (%s)' % (short_project(project), branch)
    git_url = 'http://github.com/%s/commit/%s' % (project, commit)
    body = '''Reviewed:  %s
Committed: %s
Submitter: %s
Branch:    %s\n''' % (change_url, git_url, submitter, branch)
    body = body + '\n' + git_log
    bugtask.bug.newMessage(subject=subject, content=body)

def set_in_progress(bugtask, launchpad, uploader, change_url):
    """Set bug In progress with assignee being the uploader"""

    # Retrieve uploader from Launchpad. Use email as search key if
    # provided, and only set if there is a clear match.
    try:
        searchkey = uploader[uploader.rindex("(") + 1:-1]
    except ValueError:
        searchkey = uploader
    persons = launchpad.people.findPerson(text=searchkey)
    if len(persons) == 1:
        bugtask.assignee = persons[0]

    bugtask.status = "In Progress"
    bugtask.lp_save()

def set_fix_committed(bugtask):
    """Set bug fix committed"""

    bugtask.status = "Fix Committed"
    bugtask.lp_save()

def release_fixcommitted(bugtask):
    """Set bug FixReleased if it was FixCommitted"""

    if bugtask.status == u'Fix Committed':
        bugtask.status = "Fix Released"
        bugtask.lp_save()

def tag_in_branchname(bugtask, branch):
    """Tag bug with in-branch-name tag (if name is appropriate)"""

    lp_bug = bugtask.bug
    branch_name = branch.replace('/', '-')
    if branch_name.replace('-', '').isalnum():
        lp_bug.tags = lp_bug.tags + ["in-%s" % branch_name]
        lp_bug.tags.append("in-%s" % branch_name)
        lp_bug.lp_save()

def short_project(full_project_name):
    """Return the project part of the git repository name"""
    return full_project_name.split('/')[-1]

def git2lp(full_project_name):
    """Convert Git repo name to Launchpad project"""
    project_map = {
        'openstack/python-cinderclient': 'cinder',
        'openstack/python-glanceclient': 'glance',
        'openstack/python-keystoneclient': 'keystone',
        'openstack/python-melangeclient': 'melange',
        'openstack/python-novaclient': 'nova',
        'openstack/python-quantumclient': 'quantum',
        'openstack/openstack-ci-puppet': 'openstack-ci',
        'openstack-ci/devstack-gate': 'openstack-ci',
        }
    return project_map.get(full_project_name, short_project(full_project_name))

def process_bugtask(launchpad, bugtask, git_log, args):
    """Apply changes to bugtask, based on hook / branch..."""

    if args.hook == "change-merged":
        if args.branch == 'master':
            set_fix_committed(bugtask)
        elif args.branch == 'milestone-proposed':
            release_fixcommitted(bugtask)
        else:
            tag_in_branchname(bugtask, args.branch)
        add_change_merged_message(bugtask, args.change_url, args.project,
                                  args.commit, args.submitter, args.branch,
                                  git_log)

    if args.hook == "patchset-created":
        if args.branch == 'master':
            set_in_progress(bugtask, launchpad, args.uploader, args.change_url)
        if args.patchset == '1':
            add_change_proposed_message(bugtask, args.change_url,
                                        args.project, args.branch)

def find_bugs(launchpad, git_log, args):
    """Find bugs referenced in the git log and return related bugtasks"""

    bug_regexp = r'([Bb]ug|[Ll][Pp])[\s#:]*(\d+)'
    tokens = re.split(bug_regexp, git_log)

    # Extract unique bug tasks
    bugtasks = {}
    for token in tokens:
        if re.match('^\d+$', token) and (token not in bugtasks):
            try:
                lp_bug = launchpad.bugs[token]
                for lp_task in lp_bug.bug_tasks:
                    if lp_task.bug_target_name == git2lp(args.project):
                        bugtasks[token] = lp_task
                        break
            except KeyError:
                # Unknown bug
                pass

    return bugtasks.values()

def extract_git_log(args):
    """Extract git log of all merged commits"""
    cmd = ['git',
           '--git-dir=' + BASE_DIR + '/git/' + args.project + '.git',
           'log', '--no-merges', args.commit + '^1..' + args.commit]
    return subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0]

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('hook')
    #common
    parser.add_argument('--change', default=None)
    parser.add_argument('--change-url', default=None)
    parser.add_argument('--project', default=None)
    parser.add_argument('--branch', default=None)
    parser.add_argument('--commit', default=None)
    #change-merged
    parser.add_argument('--submitter', default=None)
    #patchset-created
    parser.add_argument('--uploader', default=None)
    parser.add_argument('--patchset', default=None)

    args = parser.parse_args()

    # Connect to Launchpad
    launchpad = Launchpad.login_with('Gerrit User Sync', LPNET_SERVICE_ROOT,
                                     GERRIT_CACHE_DIR,
                                     credentials_file=GERRIT_CREDENTIALS,
                                     version='devel')

    # Get git log
    git_log = extract_git_log(args)

    # Process bugtasks found in git log
    for bugtask in find_bugs(launchpad, git_log, args):
        process_bugtask(launchpad, bugtask, git_log, args)

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


<commit_before># Copyright 2011 OpenStack Foundation
# Copyright 2012 Justin Santa Barbara
# All Rights Reserved.
#
#    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.

"""The security groups extension."""

import contextlib
import json
import webob
from webob import exc
from xml.dom import minidom

from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
from nova.compute import api as compute_api
from nova import exception
from nova.network.security_group import neutron_driver
from nova.network.security_group import openstack_driver
from nova.openstack.common.gettextutils import _

ALIAS = 'os-security-groups'
authorize = extensions.extension_authorizer('compute', 'v3:' + ALIAS)
softauth = extensions.soft_extension_authorizer('compute', 'v3:' + ALIAS)

def _authorize_context(req):
    context = req.environ['nova.context']
    authorize(context)
    return context

@contextlib.contextmanager
def translate_exceptions():
    """Translate nova exceptions to http exceptions."""
    try:
        yield
    except exception.Invalid as exp:
        msg = exp.format_message()
        raise exc.HTTPBadRequest(explanation=msg)
    except exception.SecurityGroupNotFound as exp:
        msg = exp.format_message()
        raise exc.HTTPNotFound(explanation=msg)
    except exception.InstanceNotFound as exp:
        msg = exp.format_message()
        raise exc.HTTPNotFound(explanation=msg)
    except exception.SecurityGroupLimitExceeded as exp:
        msg = exp.format_message()
        raise exc.HTTPRequestEntityTooLarge(explanation=msg)

class SecurityGroupActionController(wsgi.Controller):
    def __init__(self, *args, **kwargs):
        super(SecurityGroupActionController, self).__init__(*args, **kwargs)
        self.security_group_api = (
            openstack_driver.get_openstack_security_group_driver())
        self.compute_api = compute.API(
                                   security_group_api=self.security_group_api)

    def _parse(self, body, action):
        try:
            body = body[action]
            group_name = body['name']
        except TypeError:
            msg = _("Missing parameter dict")
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except KeyError:
            msg = _("Security group not specified")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        if not group_name or group_name.strip() == '':
            msg = _("Security group name cannot be empty")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        return group_name

    def _invoke(self, method, context, id, group_name):
        with translate_exceptions():
            instance = self.compute_api.get(context, id)
            method(context, instance, group_name)

        return webob.Response(status_int=202)

    @wsgi.action('add_security_group')
    def _add_security_group(self, req, id, body):
        context = req.environ['nova.context']
        authorize(context)

        group_name = self._parse(body, 'add_security_group')

        return self._invoke(self.security_group_api.add_to_instance,
                            context, id, group_name)

    @wsgi.action('remove_security_group')
    def _remove_security_group(self, req, id, body):
        context = req.environ['nova.context']
        authorize(context)

        group_name = self._parse(body, 'remove_security_group')

        return self._invoke(self.security_group_api.remove_from_instance,
                            context, id, group_name)

class SecurityGroupsOutputController(wsgi.Controller):
    def __init__(self, *args, **kwargs):
        super(SecurityGroupsOutputController, self).__init__(*args, **kwargs)
        self.compute_api = compute.API()
        self.security_group_api = (
            openstack_driver.get_openstack_security_group_driver())

    def _extend_servers(self, req, servers):
        # TODO(arosen) this function should be refactored to reduce duplicate
        # code and use get_instance_security_groups instead of get_db_instance.
        if not len(servers):
            return
        key = "security_groups"
        context = _authorize_context(req)
        if not openstack_driver.is_neutron_security_groups():
            for server in servers:
                instance = req.get_db_instance(server['id'])
                groups = instance.get(key)
                if groups:
                    server[key] = [{"name": group["name"]} for group in groups]
        else:
            # If method is a POST we get the security groups intended for an
            # instance from the request. The reason for this is if using
            # neutron security groups the requested security groups for the
            # instance are not in the db and have not been sent to neutron yet.
            if req.method != 'POST':
                if len(servers) == 1:
                    group = (self.security_group_api
                             .get_instance_security_groups(context,
                                                           servers[0]['id']))
                    if group:
                        servers[0][key] = group
                else:
                    sg_instance_bindings = (
                        self.security_group_api
                        .get_instances_security_groups_bindings(context))
                    for server in servers:
                        groups = sg_instance_bindings.get(server['id'])
                        if groups:
                            server[key] = groups
            # In this section of code len(servers) == 1 as you can only POST
            # one server in an API request.
            else:
                try:
                    # try converting to json
                    req_obj = json.loads(req.body)
                    # Add security group to server, if no security group was in
                    # request add default since that is the group it is part of
                    servers[0][key] = req_obj['server'].get(
                        key, [{'name': 'default'}])
                except ValueError:
                    root = minidom.parseString(req.body)
                    sg_root = root.getElementsByTagName(key)
                    groups = []
                    if sg_root:
                        security_groups = sg_root[0].getElementsByTagName(
                            'security_group')
                        for security_group in security_groups:
                            groups.append(
                                {'name': security_group.getAttribute('name')})
                    if not groups:
                        groups = [{'name': 'default'}]

                    servers[0][key] = groups

    def _show(self, req, resp_obj):
        if not softauth(req.environ['nova.context']):
            return
        if 'server' in resp_obj.obj:
            resp_obj.attach(xml=SecurityGroupServerTemplate())
            self._extend_servers(req, [resp_obj.obj['server']])

    @wsgi.extends
    def show(self, req, resp_obj, id):
        return self._show(req, resp_obj)

    @wsgi.extends
    def create(self, req, resp_obj, body):
        return self._show(req, resp_obj)

    @wsgi.extends
    def detail(self, req, resp_obj):
        if not softauth(req.environ['nova.context']):
            return
        resp_obj.attach(xml=SecurityGroupServersTemplate())
        self._extend_servers(req, list(resp_obj.obj['servers']))

class SecurityGroupsTemplateElement(xmlutil.TemplateElement):
    def will_render(self, datum):
        return "security_groups" in datum

def make_server(elem):
    secgrps = SecurityGroupsTemplateElement('security_groups')
    elem.append(secgrps)
    secgrp = xmlutil.SubTemplateElement(secgrps, 'security_group',
                                        selector="security_groups")
    secgrp.set('name')

class SecurityGroupServerTemplate(xmlutil.TemplateBuilder):
    def construct(self):
        root = xmlutil.TemplateElement('server')
        make_server(root)
        return xmlutil.SlaveTemplate(root, 1)

class SecurityGroupServersTemplate(xmlutil.TemplateBuilder):
    def construct(self):
        root = xmlutil.TemplateElement('servers')
        elem = xmlutil.SubTemplateElement(root, 'server', selector='servers')
        make_server(elem)
        return xmlutil.SlaveTemplate(root, 1)

class SecurityGroups(extensions.V3APIExtensionBase):
    """Security group support."""
    name = "SecurityGroups"
    alias = ALIAS
    namespace = "http://docs.openstack.org/compute/ext/securitygroups/api/v3"
    version = 1

    def get_controller_extensions(self):
        controller = SecurityGroupActionController()
        actions = extensions.ControllerExtension(self, 'servers', controller)
        controller = SecurityGroupsOutputController()
        output = extensions.ControllerExtension(self, 'servers', controller)
        return [actions, output]

    def get_resources(self):
        return []

class NativeSecurityGroupExceptions(object):
    @staticmethod
    def raise_invalid_property(msg):
        raise exception.Invalid(msg)

    @staticmethod
    def raise_group_already_exists(msg):
        raise exception.Invalid(msg)

    @staticmethod
    def raise_invalid_group(msg):
        raise exception.Invalid(msg)

    @staticmethod
    def raise_invalid_cidr(cidr, decoding_exception=None):
        raise exception.InvalidCidr(cidr=cidr)

    @staticmethod
    def raise_over_quota(msg):
        raise exception.SecurityGroupLimitExceeded(msg)

    @staticmethod
    def raise_not_found(msg):
        raise exception.SecurityGroupNotFound(msg)

class NativeNovaSecurityGroupAPI(NativeSecurityGroupExceptions,
                                 compute_api.SecurityGroupAPI):
    pass

class NativeNeutronSecurityGroupAPI(NativeSecurityGroupExceptions,
                                    neutron_driver.SecurityGroupAPI):
    pass
<commit_msg>Remove unsafe XML parsing<commit_after># Copyright 2011 OpenStack Foundation
# Copyright 2012 Justin Santa Barbara
# All Rights Reserved.
#
#    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.

"""The security groups extension."""

import contextlib
import json
import webob
from webob import exc

from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
from nova.compute import api as compute_api
from nova import exception
from nova.network.security_group import neutron_driver
from nova.network.security_group import openstack_driver
from nova.openstack.common.gettextutils import _
from nova.openstack.common import xmlutils

ALIAS = 'os-security-groups'
authorize = extensions.extension_authorizer('compute', 'v3:' + ALIAS)
softauth = extensions.soft_extension_authorizer('compute', 'v3:' + ALIAS)

def _authorize_context(req):
    context = req.environ['nova.context']
    authorize(context)
    return context

@contextlib.contextmanager
def translate_exceptions():
    """Translate nova exceptions to http exceptions."""
    try:
        yield
    except exception.Invalid as exp:
        msg = exp.format_message()
        raise exc.HTTPBadRequest(explanation=msg)
    except exception.SecurityGroupNotFound as exp:
        msg = exp.format_message()
        raise exc.HTTPNotFound(explanation=msg)
    except exception.InstanceNotFound as exp:
        msg = exp.format_message()
        raise exc.HTTPNotFound(explanation=msg)
    except exception.SecurityGroupLimitExceeded as exp:
        msg = exp.format_message()
        raise exc.HTTPRequestEntityTooLarge(explanation=msg)

class SecurityGroupActionController(wsgi.Controller):
    def __init__(self, *args, **kwargs):
        super(SecurityGroupActionController, self).__init__(*args, **kwargs)
        self.security_group_api = (
            openstack_driver.get_openstack_security_group_driver())
        self.compute_api = compute.API(
                                   security_group_api=self.security_group_api)

    def _parse(self, body, action):
        try:
            body = body[action]
            group_name = body['name']
        except TypeError:
            msg = _("Missing parameter dict")
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except KeyError:
            msg = _("Security group not specified")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        if not group_name or group_name.strip() == '':
            msg = _("Security group name cannot be empty")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        return group_name

    def _invoke(self, method, context, id, group_name):
        with translate_exceptions():
            instance = self.compute_api.get(context, id)
            method(context, instance, group_name)

        return webob.Response(status_int=202)

    @wsgi.action('add_security_group')
    def _add_security_group(self, req, id, body):
        context = req.environ['nova.context']
        authorize(context)

        group_name = self._parse(body, 'add_security_group')

        return self._invoke(self.security_group_api.add_to_instance,
                            context, id, group_name)

    @wsgi.action('remove_security_group')
    def _remove_security_group(self, req, id, body):
        context = req.environ['nova.context']
        authorize(context)

        group_name = self._parse(body, 'remove_security_group')

        return self._invoke(self.security_group_api.remove_from_instance,
                            context, id, group_name)

class SecurityGroupsOutputController(wsgi.Controller):
    def __init__(self, *args, **kwargs):
        super(SecurityGroupsOutputController, self).__init__(*args, **kwargs)
        self.compute_api = compute.API()
        self.security_group_api = (
            openstack_driver.get_openstack_security_group_driver())

    def _extend_servers(self, req, servers):
        # TODO(arosen) this function should be refactored to reduce duplicate
        # code and use get_instance_security_groups instead of get_db_instance.
        if not len(servers):
            return
        key = "security_groups"
        context = _authorize_context(req)
        if not openstack_driver.is_neutron_security_groups():
            for server in servers:
                instance = req.get_db_instance(server['id'])
                groups = instance.get(key)
                if groups:
                    server[key] = [{"name": group["name"]} for group in groups]
        else:
            # If method is a POST we get the security groups intended for an
            # instance from the request. The reason for this is if using
            # neutron security groups the requested security groups for the
            # instance are not in the db and have not been sent to neutron yet.
            if req.method != 'POST':
                if len(servers) == 1:
                    group = (self.security_group_api
                             .get_instance_security_groups(context,
                                                           servers[0]['id']))
                    if group:
                        servers[0][key] = group
                else:
                    sg_instance_bindings = (
                        self.security_group_api
                        .get_instances_security_groups_bindings(context))
                    for server in servers:
                        groups = sg_instance_bindings.get(server['id'])
                        if groups:
                            server[key] = groups
            # In this section of code len(servers) == 1 as you can only POST
            # one server in an API request.
            else:
                try:
                    # try converting to json
                    req_obj = json.loads(req.body)
                    # Add security group to server, if no security group was in
                    # request add default since that is the group it is part of
                    servers[0][key] = req_obj['server'].get(
                        key, [{'name': 'default'}])
                except ValueError:
                    root = xmlutils.safe_minidom_parse_string(req.body)
                    sg_root = root.getElementsByTagName(key)
                    groups = []
                    if sg_root:
                        security_groups = sg_root[0].getElementsByTagName(
                            'security_group')
                        for security_group in security_groups:
                            groups.append(
                                {'name': security_group.getAttribute('name')})
                    if not groups:
                        groups = [{'name': 'default'}]

                    servers[0][key] = groups

    def _show(self, req, resp_obj):
        if not softauth(req.environ['nova.context']):
            return
        if 'server' in resp_obj.obj:
            resp_obj.attach(xml=SecurityGroupServerTemplate())
            self._extend_servers(req, [resp_obj.obj['server']])

    @wsgi.extends
    def show(self, req, resp_obj, id):
        return self._show(req, resp_obj)

    @wsgi.extends
    def create(self, req, resp_obj, body):
        return self._show(req, resp_obj)

    @wsgi.extends
    def detail(self, req, resp_obj):
        if not softauth(req.environ['nova.context']):
            return
        resp_obj.attach(xml=SecurityGroupServersTemplate())
        self._extend_servers(req, list(resp_obj.obj['servers']))

class SecurityGroupsTemplateElement(xmlutil.TemplateElement):
    def will_render(self, datum):
        return "security_groups" in datum

def make_server(elem):
    secgrps = SecurityGroupsTemplateElement('security_groups')
    elem.append(secgrps)
    secgrp = xmlutil.SubTemplateElement(secgrps, 'security_group',
                                        selector="security_groups")
    secgrp.set('name')

class SecurityGroupServerTemplate(xmlutil.TemplateBuilder):
    def construct(self):
        root = xmlutil.TemplateElement('server')
        make_server(root)
        return xmlutil.SlaveTemplate(root, 1)

class SecurityGroupServersTemplate(xmlutil.TemplateBuilder):
    def construct(self):
        root = xmlutil.TemplateElement('servers')
        elem = xmlutil.SubTemplateElement(root, 'server', selector='servers')
        make_server(elem)
        return xmlutil.SlaveTemplate(root, 1)

class SecurityGroups(extensions.V3APIExtensionBase):
    """Security group support."""
    name = "SecurityGroups"
    alias = ALIAS
    namespace = "http://docs.openstack.org/compute/ext/securitygroups/api/v3"
    version = 1

    def get_controller_extensions(self):
        controller = SecurityGroupActionController()
        actions = extensions.ControllerExtension(self, 'servers', controller)
        controller = SecurityGroupsOutputController()
        output = extensions.ControllerExtension(self, 'servers', controller)
        return [actions, output]

    def get_resources(self):
        return []

class NativeSecurityGroupExceptions(object):
    @staticmethod
    def raise_invalid_property(msg):
        raise exception.Invalid(msg)

    @staticmethod
    def raise_group_already_exists(msg):
        raise exception.Invalid(msg)

    @staticmethod
    def raise_invalid_group(msg):
        raise exception.Invalid(msg)

    @staticmethod
    def raise_invalid_cidr(cidr, decoding_exception=None):
        raise exception.InvalidCidr(cidr=cidr)

    @staticmethod
    def raise_over_quota(msg):
        raise exception.SecurityGroupLimitExceeded(msg)

    @staticmethod
    def raise_not_found(msg):
        raise exception.SecurityGroupNotFound(msg)

class NativeNovaSecurityGroupAPI(NativeSecurityGroupExceptions,
                                 compute_api.SecurityGroupAPI):
    pass

class NativeNeutronSecurityGroupAPI(NativeSecurityGroupExceptions,
                                    neutron_driver.SecurityGroupAPI):
    pass
<|endoftext|>


<commit_before># pylint: disable=invalid-name
"""Signals related to the comments service."""

from django.dispatch import Signal
from django.db.models.signals import post_save
from django.dispatch import receiver

from openedx.core.djangoapps.course_groups.cohorts import is_course_cohorted
from openedx.core.djangoapps.course_groups.models import CourseCohortsSettings

from .utils import set_course_discussion_settings
from .models import CourseDiscussionSettings

thread_created = Signal(providing_args=['user', 'post'])
thread_edited = Signal(providing_args=['user', 'post'])
thread_voted = Signal(providing_args=['user', 'post', 'undo'])
thread_deleted = Signal(providing_args=['user', 'post', 'involved_users'])
thread_followed = Signal(providing_args=['user', 'post'])
thread_unfollowed = Signal(providing_args=['user', 'post'])
comment_created = Signal(providing_args=['user', 'post'])
comment_edited = Signal(providing_args=['user', 'post'])
comment_voted = Signal(providing_args=['user', 'post', 'undo'])
comment_deleted = Signal(providing_args=['user', 'post', 'involved_users'])
comment_endorsed = Signal(providing_args=['user', 'post'])
thread_or_comment_flagged = Signal(providing_args=['user', 'post', 'undo'])

@receiver(post_save, sender=CourseCohortsSettings)
def update_cohorted_discussions(sender, instance, **kwargs):
    from lms.djangoapps.django_comment_client.utils import enrollment_track_group_count
    try:
        course_discussion_settings = CourseDiscussionSettings.objects.get(course_id=instance.course_id)
        division_scheme = course_discussion_settings.division_scheme

        if instance.is_cohorted:
            division_scheme = CourseDiscussionSettings.COHORT
        elif division_scheme == CourseDiscussionSettings.COHORT:
            division_scheme = CourseDiscussionSettings.NONE
        elif (
            division_scheme == CourseDiscussionSettings.ENROLLMENT_TRACK and
            enrollment_track_group_count(course_discussion_settings.course_id) <= 1
        ):
            division_scheme = CourseDiscussionSettings.NONE

        setattr(course_discussion_settings, "division_scheme", division_scheme)
        setattr(course_discussion_settings, "divided_discussions", instance.cohorted_discussions)
        course_discussion_settings.save()

    except CourseDiscussionSettings.DoesNotExist:
        set_course_discussion_settings(
            course_key=instance.course_id,
            divided_discussions=instance.cohorted_discussions,
        )
<commit_msg>Fix import of dicussion django_comment_client. (#1948)<commit_after># pylint: disable=invalid-name
"""Signals related to the comments service."""

from django.dispatch import Signal
from django.db.models.signals import post_save
from django.dispatch import receiver

from openedx.core.djangoapps.course_groups.cohorts import is_course_cohorted
from openedx.core.djangoapps.course_groups.models import CourseCohortsSettings

from .utils import set_course_discussion_settings
from .models import CourseDiscussionSettings

thread_created = Signal(providing_args=['user', 'post'])
thread_edited = Signal(providing_args=['user', 'post'])
thread_voted = Signal(providing_args=['user', 'post', 'undo'])
thread_deleted = Signal(providing_args=['user', 'post', 'involved_users'])
thread_followed = Signal(providing_args=['user', 'post'])
thread_unfollowed = Signal(providing_args=['user', 'post'])
comment_created = Signal(providing_args=['user', 'post'])
comment_edited = Signal(providing_args=['user', 'post'])
comment_voted = Signal(providing_args=['user', 'post', 'undo'])
comment_deleted = Signal(providing_args=['user', 'post', 'involved_users'])
comment_endorsed = Signal(providing_args=['user', 'post'])
thread_or_comment_flagged = Signal(providing_args=['user', 'post', 'undo'])

@receiver(post_save, sender=CourseCohortsSettings)
def update_cohorted_discussions(sender, instance, **kwargs):
    from lms.djangoapps.discussion.django_comment_client.utils import enrollment_track_group_count
    try:
        course_discussion_settings = CourseDiscussionSettings.objects.get(course_id=instance.course_id)
        division_scheme = course_discussion_settings.division_scheme

        if instance.is_cohorted:
            division_scheme = CourseDiscussionSettings.COHORT
        elif division_scheme == CourseDiscussionSettings.COHORT:
            division_scheme = CourseDiscussionSettings.NONE
        elif (
            division_scheme == CourseDiscussionSettings.ENROLLMENT_TRACK and
            enrollment_track_group_count(course_discussion_settings.course_id) <= 1
        ):
            division_scheme = CourseDiscussionSettings.NONE

        setattr(course_discussion_settings, "division_scheme", division_scheme)
        setattr(course_discussion_settings, "divided_discussions", instance.cohorted_discussions)
        course_discussion_settings.save()

    except CourseDiscussionSettings.DoesNotExist:
        set_course_discussion_settings(
            course_key=instance.course_id,
            divided_discussions=instance.cohorted_discussions,
        )
<|endoftext|>


<commit_before>import logging

from .views import IndexView
from filters import TemplateFilters
from flask import Blueprint
from flask.ext.babelpkg import gettext as _gettext, lazy_gettext
from flask.ext.appbuilder.babel.manager import BabelManager
from flask.ext.appbuilder import translations
from .security.manager import SecurityManager
from menu import Menu

log = logging.getLogger(__name__)

class BaseApp(object):
    """
        This is the base class for the all framework.
        Will hold your flask app object, all your views, and security classes.

        initialize your application like this::

            app = Flask(__name__)
            app.config.from_object('config')
            db = SQLAlchemy(app)
            baseapp = BaseApp(app, db)

    """
    lst_baseview = []
    app = None
    db = None

    sm = None
    """ Security Manager """
    bm = None
    """ Babel Manager """
    app_name = ""
    app_theme = ''
    app_icon = None

    menu = None
    indexview = None

    static_folder = None
    static_url_path = None

    template_filters = None

    languages = None
    admin = None
    _gettext = _gettext

    def __init__(self, app, db,
                    menu = None,
                    indexview = None,
                    static_folder='static/appbuilder',
                    static_url_path='/appbuilder'):
        """
            BaseApp constructor

            :param app:
                The flask app object
            :param db:
                The SQLAlchemy db object
            :param menu:
                optional, a previous contructed menu
            :param indexview:
                optional, your customized indexview
            :param static_folder:
                optional, your override for the global static folder
            :param static_url_path:
                optional, your override for the global static url path
        """
        self.app = app
        self.db = db

        self.sm = SecurityManager(app, db.session)
        self.bm = BabelManager(app, pkg_translations=translations)

        if menu:
            self.menu = menu
            self._add_menu_permissions()
        else:
            self.menu = Menu()

        self.app.before_request(self.sm.before_request)

        self._init_config_parameters()
        self.indexview = indexview or IndexView
        self.static_folder = static_folder
        self.static_url_path = static_url_path
        self._add_admin_views()
        self._add_global_static()
        self._add_global_filters()

        # Creating Developer's models
        self.db.create_all()

    def _init_config_parameters(self):
        if 'APP_NAME' in self.app.config:
            self.app_name = self.app.config['APP_NAME']
        else:
            self.app_name = 'F.A.B.'
        if 'APP_ICON' in self.app.config:
            self.app_icon = self.app.config['APP_ICON']
        if 'APP_THEME' in self.app.config:
            self.app_theme = self.app.config['APP_THEME']
        else:
            self.app_theme = ''
        if 'LANGUAGES' in self.app.config:
            self.languages = self.app.config['LANGUAGES']
        else:
            self.languages = {
                'en': {'flag':'gb', 'name':'English'},
                }

    def _add_global_filters(self):
        self.template_filters = TemplateFilters(self.app, self.sm)

    def _add_global_static(self):
        bp = Blueprint('baseapp', __name__, url_prefix='/static',
                template_folder='templates', static_folder = self.static_folder, static_url_path = self.static_url_path)
        self.app.register_blueprint(bp)

    def _add_admin_views(self):
        self.indexview = self.indexview()
        self.add_view_no_menu(self.indexview)
        self.bm.register_views(self)
        self.sm.register_views(self)

    def _init_view_session(self, baseview_class):
        if baseview_class.datamodel.session == None:
            baseview_class.datamodel.session = self.db.session
        return baseview_class()

    def _add_permissions_menu(self, name):
        try:
            self.sm.add_permissions_menu(name)
        except:
            log.error("Add Permission on Menu Error")

    def _add_menu_permissions(self):
        for category in self.menu.get_list():
            self._add_permissions_menu(category.name)
            for item in category.childs:
                self._add_permissions_menu(item.name)

    def add_view(self, baseview, name, href = "", icon = "", category = ""):
        """
            Add your views associated with menus using this method.

            :param baseview:
                A BaseView type class instantiated.
            :param name:
                The string name that will be displayed on the menu.
            :param href:
                Override the generated href for the menu. if non provided default_view from view will be set as href.
            :param icon:
                Font-Awesome icon name, optional.
            :param category:
                The menu category where the menu will be included, if non provided the view will be acessible as a top menu.

            Examples::

                baseapp = BaseApp(app, db)
                # Register a view, rendering a top menu without icon
                baseapp.add_view(MyGeneralView, "My View")
                # Register a view, a submenu "Other View" from "Other" with a phone icon
                baseapp.add_view(MyOtherGeneralView, "Other View", icon='fa-phone', category="Others")
                # Add a link
                baseapp.add_link("google", href="www.google.com", icon = "fa-google-plus")
        """
        log.info("Registering class %s on menu %s.%s" % (baseview.__class__.__name__, category,name))
        if baseview not in self.lst_baseview:
            baseview.baseapp = self
            self.lst_baseview.append(baseview)
            self.register_blueprint(baseview)
            self._add_permission(baseview)
        self.add_link(name = name, href = href, icon = icon, category = category, baseview = baseview)

    def add_link(self, name, href, icon = "", category = "", baseview = None):
        """
            Add your own links to menu using this method

            :param name:
                The string name that will be displayed on the menu.
            :param href:
                Override the generated href for the menu.
            :param icon:
                Bootstrap included icon name
            :param category:
                The menu category where the menu will be included
        """
        self.menu.add_link(name = name, href = href, icon = icon,
                        category = category, baseview = baseview)
        self._add_permissions_menu(name)
        if category:
            self._add_permissions_menu(category)

    def add_separator(self, category):
        """
            Add a separator to the menu, you will sequentially create the menu

            :param category:
                The menu category where the separator will be included.
        """
        self.menu.add_separator(category)

    def add_view_no_menu(self, baseview, endpoint = None, static_folder = None):
        """
            Add your views without creating a menu.

            :param baseview:
                A BaseView type class instantiated.

        """
        if baseview not in self.lst_baseview:
            baseview.baseapp = self
            self.lst_baseview.append(baseview)
            self.register_blueprint(baseview, endpoint = endpoint, static_folder = static_folder)
            self._add_permission(baseview)

    def _add_permission(self, baseview):
        try:
            self.sm.add_permissions_view(baseview.base_permissions, baseview.__class__.__name__)
        except:
            log.error("Add Permission on View Error")

    def register_blueprint(self, baseview, endpoint = None, static_folder = None):
        self.app.register_blueprint(baseview.create_blueprint(self,  endpoint = endpoint, static_folder = static_folder))

    def _get_view(self, class_name):
        for view in self.lst_baseview:
            log.debug('_get_view %s %s' % (str(view.__class__.__name__), str(class_name)))
            if isinstance(view, class_name):
                log.debug('_get_view GOT IT!')
                return view

<commit_msg>Update baseapp.py<commit_after>import logging

from .views import IndexView
from filters import TemplateFilters
from flask import Blueprint
from flask.ext.babelpkg import gettext as _gettext, lazy_gettext
from flask.ext.appbuilder.babel.manager import BabelManager
from flask.ext.appbuilder import translations
from .security.manager import SecurityManager
from menu import Menu

log = logging.getLogger(__name__)

class BaseApp(object):
    """
        This is the base class for the all framework.
        Will hold your flask app object, all your views, and security classes.

        initialize your application like this::

            app = Flask(__name__)
            app.config.from_object('config')
            db = SQLAlchemy(app)
            baseapp = BaseApp(app, db)

    """
    lst_baseview = []
    app = None
    db = None

    sm = None
    """ Security Manager """
    bm = None
    """ Babel Manager """
    app_name = ""
    app_theme = ''
    app_icon = None

    menu = None
    indexview = None

    static_folder = None
    static_url_path = None

    template_filters = None

    languages = None
    admin = None
    _gettext = _gettext

    def __init__(self, app, db,
                    menu = None,
                    indexview = None,
                    static_folder='static/appbuilder',
                    static_url_path='/appbuilder'):
        """
            BaseApp constructor

            :param app:
                The flask app object
            :param db:
                The SQLAlchemy db object
            :param menu:
                optional, a previous contructed menu
            :param indexview:
                optional, your customized indexview
            :param static_folder:
                optional, your override for the global static folder
            :param static_url_path:
                optional, your override for the global static url path
        """
        self.app = app
        self.db = db

        self.sm = SecurityManager(app, db.session)
        self.bm = BabelManager(app, pkg_translations=translations)

        if menu:
            self.menu = menu
            self._add_menu_permissions()
        else:
            self.menu = Menu()

        self.app.before_request(self.sm.before_request)

        self._init_config_parameters()
        self.indexview = indexview or IndexView
        self.static_folder = static_folder
        self.static_url_path = static_url_path
        self._add_admin_views()
        self._add_global_static()
        self._add_global_filters()

        # Creating Developer's models
        self.db.create_all()

    def _init_config_parameters(self):
        if 'APP_NAME' in self.app.config:
            self.app_name = self.app.config['APP_NAME']
        else:
            self.app_name = 'F.A.B.'
        if 'APP_ICON' in self.app.config:
            self.app_icon = self.app.config['APP_ICON']
        if 'APP_THEME' in self.app.config:
            self.app_theme = self.app.config['APP_THEME']
        else:
            self.app_theme = ''
        if 'LANGUAGES' in self.app.config:
            self.languages = self.app.config['LANGUAGES']
        else:
            self.languages = {
                'en': {'flag':'gb', 'name':'English'},
                }

    def _add_global_filters(self):
        self.template_filters = TemplateFilters(self.app, self.sm)

    def _add_global_static(self):
        bp = Blueprint('baseapp', __name__, url_prefix='/static',
                template_folder='templates', static_folder = self.static_folder, static_url_path = self.static_url_path)
        self.app.register_blueprint(bp)

    def _add_admin_views(self):
        self.indexview = self.indexview()
        self.add_view_no_menu(self.indexview)
        self.bm.register_views(self)
        self.sm.register_views(self)

    def _init_view_session(self, baseview_class):
        if baseview_class.datamodel.session == None:
            baseview_class.datamodel.session = self.db.session
        return baseview_class()

    def _add_permissions_menu(self, name):
        try:
            self.sm.add_permissions_menu(name)
        except:
            log.error("Add Permission on Menu Error")

    def _add_menu_permissions(self):
        for category in self.menu.get_list():
            self._add_permissions_menu(category.name)
            for item in category.childs:
                self._add_permissions_menu(item.name)

    def add_view(self, baseview, name, href = "", icon = "", category = ""):
        """
            Add your views associated with menus using this method.

            :param baseview:
                A BaseView type class instantiated.
            :param name:
                The string name that will be displayed on the menu.
            :param href:
                Override the generated href for the menu. if non provided default_view from view will be set as href.
            :param icon:
                Font-Awesome icon name, optional.
            :param category:
                The menu category where the menu will be included, if non provided the view will be acessible as a top menu.

            Examples::

                baseapp = BaseApp(app, db)
                # Register a view, rendering a top menu without icon
                baseapp.add_view(MyGeneralView, "My View")
                # Register a view, a submenu "Other View" from "Other" with a phone icon
                baseapp.add_view(MyOtherGeneralView, "Other View", icon='fa-phone', category="Others")
                # Add a link
                baseapp.add_link("google", href="www.google.com", icon = "fa-google-plus")
        """
        log.info("Registering class %s on menu %s.%s" % (baseview.__class__.__name__, category,name))
        if baseview not in self.lst_baseview:
            baseview.baseapp = self
            self.lst_baseview.append(baseview)
            self._set_ref_related_views(baseview)
            self.register_blueprint(baseview)
            self._add_permission(baseview)
        self.add_link(name = name, href = href, icon = icon, category = category, baseview = baseview)

    def add_link(self, name, href, icon = "", category = "", baseview = None):
        """
            Add your own links to menu using this method

            :param name:
                The string name that will be displayed on the menu.
            :param href:
                Override the generated href for the menu.
            :param icon:
                Bootstrap included icon name
            :param category:
                The menu category where the menu will be included
        """
        self.menu.add_link(name = name, href = href, icon = icon,
                        category = category, baseview = baseview)
        self._add_permissions_menu(name)
        if category:
            self._add_permissions_menu(category)

    def add_separator(self, category):
        """
            Add a separator to the menu, you will sequentially create the menu

            :param category:
                The menu category where the separator will be included.
        """
        self.menu.add_separator(category)

    def add_view_no_menu(self, baseview, endpoint = None, static_folder = None):
        """
            Add your views without creating a menu.

            :param baseview:
                A BaseView type class instantiated.

        """
        if baseview not in self.lst_baseview:
            baseview.baseapp = self
            self.lst_baseview.append(baseview)
            self._set_ref_related_views(baseview)
            self.register_blueprint(baseview, endpoint = endpoint, static_folder = static_folder)
            self._add_permission(baseview)

    def _add_permission(self, baseview):
        try:
            self.sm.add_permissions_view(baseview.base_permissions, baseview.__class__.__name__)
        except:
            log.error("Add Permission on View Error")

    def register_blueprint(self, baseview, endpoint = None, static_folder = None):
        self.app.register_blueprint(baseview.create_blueprint(self,  endpoint = endpoint, static_folder = static_folder))

    def _set_ref_related_views(self, view):
        if hasattr(view, 'related_views'):
            for rel_class in view.related_view:
                for v in self.lst_baseviews:
                    if isinstance(v, rel_class) and v not in view._related_views:
                        log.debug('_get_view GOT IT!')
                        view._related_views.append(v)

<|endoftext|>


<commit_before>from app import app
from flask.ext.appbuilder.security.models import is_menu_public, is_item_public
from flask.ext.appbuilder.models.datamodel import SQLAModel
from flask import g, request, url_for
from flask.ext.login import current_user

def app_template_filter(filter_name=''):
    """
        Use this decorator to expose views in your view classes.
    """
    def wrap(f):
        if not hasattr(f, '_filter'):
            f._filter = filter_name
        return f
    return wrap

class TemplateFilters(object):

    def __init__(self, app):
        for attr_name in dir(self):
            if hasattr(getattr(self, attr_name),'_filter'):
                attr = getattr(self, attr_name)
                app.jinja_env.filters[attr._filter] = attr

    @app_template_filter('link_order')
    """
    Arguments are passed like: _oc_<VIEW_NAME>=<COL_NAME>&_od_<VIEW_NAME>='asc'|'desc'
    """
    def link_order_filter(self, column, , generalview_name):
        new_args = request.view_args.copy()
        args = request.args.copy()
        if ('_oc_') in args:
            args['_oc_'] = column
            if args.get('_od_') == 'asc':
                args['_od_' + generalview_name] = 'desc'
            else:
                args['_od_' + generalview_name] = 'asc'
        else:
            args['_oc_' + generalview_name] = column
            args['_od_' + generalview_name] = 'asc'
        return url_for(request.endpoint,**dict(new_args.items() + args.to_dict().items()))

    @app_template_filter('link_page')
    """
    Arguments are passed like: page_<VIEW_NAME>=<PAGE_NUMBER>
    """
    def link_page_filter(self, page, generalview_name):

        new_args = request.view_args.copy()
        args = request.args.copy()
        args['page_' + generalview_name] = page
        return url_for(request.endpoint,**dict(new_args.items() + args.to_dict().items()))

    @app_template_filter('get_link_next')
    def get_link_next_filter(self, s):
        return request.args.get('next')

    # to improve
    @app_template_filter('set_link_filters')
    def set_link_filters_filter(self, path, filters, pk):
        lnkstr = path

        for _filter in filters:
            lnkstr = lnkstr + '&_flt_' + _filter + '=' + str(pk)
        return lnkstr

    @app_template_filter('get_link_order')
    def get_link_order_filter(self, s):
        if request.args.get('_oc_') == s:
            order_direction = request.args.get('_od_')
            if (order_direction):
                if (order_direction == 'asc'):
                    return 2
                else:
                    return 1
        else:
            return 0

    @app_template_filter('get_attr')
    def get_attr_filter(self, obj, item):
        return getattr(obj, item)

    @app_template_filter('is_menu_visible')
    def is_menu_visible(self, item):
        if current_user.is_authenticated():
            if is_menu_public(item) or g.user.has_menu_access(item.name):
                return True
            else:
                return False
        else:
            if is_menu_public(item.name):
                return True
            else:
                return False

    @app_template_filter('is_item_visible')
    def is_item_visible(self, permission, item):
        if current_user.is_authenticated():
            if g.user.has_permission_on_view(permission, item):
                return True
            else:
                return False
        else:
            if is_item_public(permission, item):
                return True
            else:
                return False
<commit_msg>Update filters.py<commit_after>from app import app
from flask.ext.appbuilder.security.models import is_menu_public, is_item_public
from flask.ext.appbuilder.models.datamodel import SQLAModel
from flask import g, request, url_for
from flask.ext.login import current_user

def app_template_filter(filter_name=''):
    """
        Use this decorator to expose views in your view classes.
    """
    def wrap(f):
        if not hasattr(f, '_filter'):
            f._filter = filter_name
        return f
    return wrap

class TemplateFilters(object):

    def __init__(self, app):
        for attr_name in dir(self):
            if hasattr(getattr(self, attr_name),'_filter'):
                attr = getattr(self, attr_name)
                app.jinja_env.filters[attr._filter] = attr

    @app_template_filter('link_order')
    def link_order_filter(self, column, , generalview_name):
    """
    Arguments are passed like: _oc_<VIEW_NAME>=<COL_NAME>&_od_<VIEW_NAME>='asc'|'desc'
    """
        new_args = request.view_args.copy()
        args = request.args.copy()
        if ('_oc_') in args:
            args['_oc_'] = column
            if args.get('_od_') == 'asc':
                args['_od_' + generalview_name] = 'desc'
            else:
                args['_od_' + generalview_name] = 'asc'
        else:
            args['_oc_' + generalview_name] = column
            args['_od_' + generalview_name] = 'asc'
        return url_for(request.endpoint,**dict(new_args.items() + args.to_dict().items()))

    @app_template_filter('link_page')
    def link_page_filter(self, page, generalview_name):
    """
    Arguments are passed like: page_<VIEW_NAME>=<PAGE_NUMBER>
    """
        new_args = request.view_args.copy()
        args = request.args.copy()
        args['page_' + generalview_name] = page
        return url_for(request.endpoint,**dict(new_args.items() + args.to_dict().items()))

    @app_template_filter('get_link_next')
    def get_link_next_filter(self, s):
        return request.args.get('next')

    # to improve
    @app_template_filter('set_link_filters')
    def set_link_filters_filter(self, path, filters, pk):
        lnkstr = path

        for _filter in filters:
            lnkstr = lnkstr + '&_flt_' + _filter + '=' + str(pk)
        return lnkstr

    @app_template_filter('get_link_order')
    def get_link_order_filter(self, s):
        if request.args.get('_oc_') == s:
            order_direction = request.args.get('_od_')
            if (order_direction):
                if (order_direction == 'asc'):
                    return 2
                else:
                    return 1
        else:
            return 0

    @app_template_filter('get_attr')
    def get_attr_filter(self, obj, item):
        return getattr(obj, item)

    @app_template_filter('is_menu_visible')
    def is_menu_visible(self, item):
        if current_user.is_authenticated():
            if is_menu_public(item) or g.user.has_menu_access(item.name):
                return True
            else:
                return False
        else:
            if is_menu_public(item.name):
                return True
            else:
                return False

    @app_template_filter('is_item_visible')
    def is_item_visible(self, permission, item):
        if current_user.is_authenticated():
            if g.user.has_permission_on_view(permission, item):
                return True
            else:
                return False
        else:
            if is_item_public(permission, item):
                return True
            else:
                return False
<|endoftext|>


<commit_before>#!/usr/bin/env python
# coding=utf8

from flask import Blueprint, current_app, url_for

try:
    from wtforms.fields import HiddenField
except ImportError:
    def is_hidden_field_filter(field):
        raise RuntimeError('WTForms is not installed.')
else:
    def is_hidden_field_filter(field):
        return isinstance(field, HiddenField)

def bootstrap_find_resource(filename, use_minified=None):
    # FIXME: get rid of this function and instead manipulate the flask routing
    #        system
    config = current_app.config

    if None == use_minified:
        use_minified = config['BOOTSTRAP_USE_MINIFIED']

    if use_minified:
        filename = '%s.min.%s' % tuple(filename.rsplit('.', 1))

    if not config['BOOTSTRAP_USE_CDN']:
        return url_for('bootstrap.static', filename=filename)
    else:
        baseurl = config['BOOTSTRAP_CDN_BASEURL']
        if baseurl.startswith('//') and config['BOOTSTRAP_CDN_PREFER_SSL']:
            baseurl = 'https:%s' % baseurl
        return baseurl + filename

class Bootstrap(object):
    def __init__(self, app=None):
        if app is not None:
            self.init_app(app)

    def init_app(self, app):
        app.config.setdefault('BOOTSTRAP_USE_MINIFIED', True)
        app.config.setdefault('BOOTSTRAP_JQUERY_VERSION', '1')
        app.config.setdefault('BOOTSTRAP_HTML5_SHIM', True)
        app.config.setdefault('BOOTSTRAP_GOOGLE_ANALYTICS_ACCOUNT', None)
        app.config.setdefault('BOOTSTRAP_USE_CDN', False)
        app.config.setdefault('BOOTSTRAP_CDN_PREFER_SSL', True)
        app.config.setdefault(
            'BOOTSTRAP_CDN_BASEURL',
            '//netdna.bootstrapcdn.com/twitter-bootstrap/2.1.1/'
        )

        blueprint = Blueprint(
            'bootstrap',
            __name__,
            template_folder='templates',
            static_folder='static',
            static_url_path=app.static_url_path + '/bootstrap')

        app.register_blueprint(blueprint)

        app.jinja_env.filters['bootstrap_is_hidden_field'] =\
            is_hidden_field_filter
        app.jinja_env.filters['bootstrap_find_resource'] =\
            bootstrap_find_resource
<commit_msg>Fixed wrong version of bootstrap using CDN.<commit_after>#!/usr/bin/env python
# coding=utf8

from flask import Blueprint, current_app, url_for

try:
    from wtforms.fields import HiddenField
except ImportError:
    def is_hidden_field_filter(field):
        raise RuntimeError('WTForms is not installed.')
else:
    def is_hidden_field_filter(field):
        return isinstance(field, HiddenField)

def bootstrap_find_resource(filename, use_minified=None):
    # FIXME: get rid of this function and instead manipulate the flask routing
    #        system
    config = current_app.config

    if None == use_minified:
        use_minified = config['BOOTSTRAP_USE_MINIFIED']

    if use_minified:
        filename = '%s.min.%s' % tuple(filename.rsplit('.', 1))

    if not config['BOOTSTRAP_USE_CDN']:
        return url_for('bootstrap.static', filename=filename)
    else:
        baseurl = config['BOOTSTRAP_CDN_BASEURL']
        if baseurl.startswith('//') and config['BOOTSTRAP_CDN_PREFER_SSL']:
            baseurl = 'https:%s' % baseurl
        return baseurl + filename

class Bootstrap(object):
    def __init__(self, app=None):
        if app is not None:
            self.init_app(app)

    def init_app(self, app):
        app.config.setdefault('BOOTSTRAP_USE_MINIFIED', True)
        app.config.setdefault('BOOTSTRAP_JQUERY_VERSION', '1')
        app.config.setdefault('BOOTSTRAP_HTML5_SHIM', True)
        app.config.setdefault('BOOTSTRAP_GOOGLE_ANALYTICS_ACCOUNT', None)
        app.config.setdefault('BOOTSTRAP_USE_CDN', False)
        app.config.setdefault('BOOTSTRAP_CDN_PREFER_SSL', True)
        app.config.setdefault(
            'BOOTSTRAP_CDN_BASEURL',
            '//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/'
        )

        blueprint = Blueprint(
            'bootstrap',
            __name__,
            template_folder='templates',
            static_folder='static',
            static_url_path=app.static_url_path + '/bootstrap')

        app.register_blueprint(blueprint)

        app.jinja_env.filters['bootstrap_is_hidden_field'] =\
            is_hidden_field_filter
        app.jinja_env.filters['bootstrap_find_resource'] =\
            bootstrap_find_resource
<|endoftext|>