def test_get_ownerships(self):

        # There should be no ownerships declared on the spec.
        ownerships = _db_get_ownerships("http://justatest.com")
        assert len(ownerships) == 0

        # We now declare 1 ownership.
        _db_declare_ownership(self.tapp, "test_TEST")
        ownerships = _db_get_ownerships("http://justatest.com")
        assert len(ownerships) == 1

        # We now create a second app for further testing.
        app2 = api.create_app("UTApp2", "translate", "{'spec':'http://justatest.com'}")
        api.add_var(app2, "spec", "http://justatest.com")

        # Ensure we still have 1 ownership.
        ownerships = _db_get_ownerships("http://justatest.com")
        assert len(ownerships) == 1

        # Add a second ownership for another language.
        _db_declare_ownership(app2, "testen_TESTEN")
        ownerships = _db_get_ownerships("http://justatest.com")
        assert len(ownerships) == 2

        # Ensure that the ownerships are right.
        firstOwnership = next(o for o in ownerships if o.value == "test_TEST")
        assert firstOwnership.app == self.tapp
        secondOwnership = next(o for o in ownerships if o.value == "testen_TESTEN")
        assert secondOwnership.app == app2
Exemplo n.º 2
0
    def test_add_get_var(self):
        api.add_var(self.tapp, "TestVar", "TestValue")
        vars = api.get_all_vars(self.tapp)

        assert len(vars) == 1
        myvar = vars[0]
        assert myvar.name == "TestVar"
        assert myvar.value == "TestValue"
Exemplo n.º 3
0
    def test_add_get_var(self):
        api.add_var(self.tapp, "TestVar", "TestValue")
        vars = api.get_all_vars(self.tapp)

        assert len(vars) == 1
        myvar = vars[0]
        assert myvar.name == "TestVar"
        assert myvar.value == "TestValue"
    def test_translate_default_autoaccept(self):
        with self.flask_app:
            rv = self.login("testuser", "password")
            app = api.create_app("UTApp", "translate", '{"spec":"http://justatest.com", "bundles":{}}')
            api.add_var(app, "spec", "http://justatest.com")

            # Test that autoaccept is True (it's the default).
            bm = BundleManager.create_from_existing_app(json.loads(app.data))
            assert bm.get_autoaccept() == True
Exemplo n.º 5
0
def _db_declare_ownership(owner_app, lang_code):
    """
    Declares ownership over a given Spec and Langcode. The CALLER is responsible of ensuring
    that no other owner for that spec and lang code exists before invoking this method.

    @param owner_app: Owner App for the language.
    @param lang_code: Language code to own.
    @return: None.
    """
    add_var(owner_app, "ownership", lang_code)
Exemplo n.º 6
0
def _db_declare_ownership(owner_app, lang_code):
    """
    Declares ownership over a given Spec and Langcode. The CALLER is responsible of ensuring
    that no other owner for that spec and lang code exists before invoking this method.

    @param owner_app: Owner App for the language.
    @param lang_code: Language code to own.
    @return: None.
    """
    add_var(owner_app, "ownership", lang_code)
    def test_get_proposals(self):

        proposals = _db_get_proposals(self.tapp)
        len(proposals) == 0

        # We add a fake proposal for the test app we have.
        # The data for the proposal is NOT valid, but shouldn't affect this test.
        api.add_var(self.tapp, "proposal", "{}")
        api.add_var(self.tapp, "proposal", "{}")
        proposals = _db_get_proposals(self.tapp)
        assert len(proposals) == 2
Exemplo n.º 8
0
def test(appid):
    # Remove all existing testvars.
    for v in get_all_vars(appid):
        remove_var(v)

    add_var(appid, "testvar", "Test Value")
    vars = get_all_vars(appid)

    var = set_var(appid, "testvar", "Hello")

    return repr(vars)
Exemplo n.º 9
0
def test(appid):
    # Remove all existing testvars.
    for v in get_all_vars(appid):
        remove_var(v)

    add_var(appid, "testvar", "Test Value")
    vars = get_all_vars(appid)

    var = set_var(appid, "testvar", "Hello")

    return repr(vars)
Exemplo n.º 10
0
    def test_find_unique_name_for_app(self):
        # There is no conflict, so the name should be exactly the chosen one.
        name = _find_unique_name_for_app("UTAPPDoesntExist")
        assert name == "UTAPPDoesntExist"

        # There is a conflict, so the name should include a number, starting at 1.
        name = _find_unique_name_for_app("UTApp")
        assert name == "UTApp (1)"

        # We create a new app so that we can force a second conflict.
        app2 = api.create_app("UTApp (1)", "translate", "{'spec':'http://justatest.com'}")
        api.add_var(app2, "spec", "http://justatest.com")
        name = _find_unique_name_for_app("UTApp")
        assert name == "UTApp (2)"
Exemplo n.º 11
0
    def test_get_diff_specs(self):
        """
        Check that we can retrieve a list of all specs from the DB. Because we don't re-create
        a test DB explicitly, the checks are limited.
        """
        specs = _db_get_diff_specs()
        assert "http://justatest.com" in specs

        app2 = api.create_app("UTApp2", "translate", "{'spec':'http://justatest.com'}")
        api.add_var(app2, "spec", "ATESTSPEC")

        specs = _db_get_diff_specs()
        assert "http://justatest.com" in specs
        assert "ATESTSPEC" in specs
Exemplo n.º 12
0
def adapt_duplicate(appid):
    app = get_app(appid)
    if app is None:
        return render_template("composers/errors.html",
                               message="Application not found")

    form = DuplicationForm()

    if form.validate_on_submit():

        # Protect against CSRF attacks.
        if not verify_csrf(request):
            return render_template(
                "composers/errors.html",
                message=
                "Request does not seem to come from the right source (csrf check)"
            ), 400

        existing_app = get_app_by_name(form.name.data)
        if existing_app:
            if not form.name.errors:
                form.name.errors = []
            form.name.errors.append(
                lazy_gettext("You already have an application with this name"))
        else:
            new_app = create_app(form.name.data, 'adapt', app.spec.url,
                                 app.data)
            for appvar in app.appvars:  # Copy every appvar for the original app as well.
                add_var(new_app, appvar.name, appvar.value)

            return redirect(url_for('.adapt_edit', appid=new_app.unique_id))

    if not form.name.data:
        counter = 2
        potential_name = ''
        while counter < 1000:
            potential_name = '%s (%s)' % (app.name, counter)

            existing_app = get_app_by_name(potential_name)
            if not existing_app:
                break
            counter += 1

        form.name.data = potential_name

    return render_template("composers/adapt/duplicate.html",
                           form=form,
                           app=app)
Exemplo n.º 13
0
    def test_update_var(self):
        var = api.add_var(self.tapp, "TestVar1", "TestValue1")

        assert var.value == "TestValue1"

        api.set_var(self.tapp, "TestVar1", "NewValue")
        assert var.value == "NewValue"
    def test_conflicting_composer(self):
        """
        Check that there is no mistake when there is a conflicting composer using the same appvar names.
        """
        # We now declare 1 ownership.
        _db_declare_ownership(self.tapp, "test_TEST")
        ownerships = _db_get_ownerships("http://justatest.com")
        assert len(ownerships) == 1

        # We now create a non-translate app.
        app2 = api.create_app("UTApp2", "dummy", "http://justatest.com", "{'spec':'http://justatest.com'}")
        api.add_var(app2, "ownership", "test_TEST")

        # Make sure that even though we added an ownership on an app with the same spec, it won't be
        # taken into account because it is a DUMMY and not a TRANSLATE composer.
        assert len(ownerships) == 1
Exemplo n.º 15
0
    def test_update_var(self):
        var = api.add_var(self.tapp, "TestVar1", "TestValue1")

        assert var.value == "TestValue1"

        api.set_var(self.tapp, "TestVar1", "NewValue")
        assert var.value == "NewValue"
Exemplo n.º 16
0
    def test_get_spec_apps(self):
        apps = _db_get_spec_apps("http://justatest.com")
        assert len(apps) == 1

        # Add a second spec (which should NOT be retrieved) for further testing.
        app2 = api.create_app("UTApp (1)", "translate", "{'spec':'http://different.com'}")
        api.add_var(app2, "spec", "http://different.com")
        apps = _db_get_spec_apps("http://justatest.com")
        # Should still be 1. The new app is of a different spec.
        assert len(apps) == 1

        # Add a second spec (which should NOT be retrieved) for further testing.
        app2 = api.create_app("UTApp2", "translate", "{'spec':'http://justatest.com'}")
        api.add_var(app2, "spec", "http://justatest.com")
        apps = _db_get_spec_apps("http://justatest.com")
        # Should now be 2.
        assert len(apps) == 2
    def test_delete_is_csrf_protected(self):
        """
        Ensure that app delete is not vulnerable to CSRF exploits.
        """
        # Create utapp1 in utuser1
        with self.flask_app:
            rv = self.login("utuser1", "password")
            assert session["logged_in"] == True
            app = api.create_app("utapp1", "translate", '{"spec":"http://justatest.com", "bundles":{}}')
            api.add_var(app, "spec", "http://justatest.com")
            self.appid = app.unique_id

        # Try to delete the app with the CSRF enabled.
        flask_instance.config["CSRF_ENABLED"] = True
        rv = self.flask_app.post("/composers/translate/delete", data={"appid": self.appid, "delete": "Delete"},
            follow_redirects=True)
        assert rv.status_code == 400  # We are not complying with the CSRF code, so an error 400 should be returned.
Exemplo n.º 18
0
    def setUp(self):
        appcomposer.app.config['DEBUG'] = True
        appcomposer.app.config['TESTING'] = True
        appcomposer.app.config['CSRF_ENABLED'] = False
        appcomposer.app.config["SECRET_KEY"] = 'secret'
        self.flask_app = appcomposer.app.test_client()
        self.flask_app.__enter__()

        rv = self.login("testuser", "password")

        # In case the test failed before, start from a clean state.
        self._cleanup()

        # Create an App for the tests.
        self.tapp = api.create_app("UTApp", "translate", '{"spec":"http://justatest.com"}')

        # Because it's a translate app it needs an spec when it is created, and that is in fact required by some of the tests.
        api.add_var(self.tapp, "spec", "http://justatest.com")
Exemplo n.º 19
0
    def test_transfer_ownership(self):
        """
        Tests the method to transfer ownership.
        """
        # We now declare 1 ownership.
        _db_declare_ownership(self.tapp, "test_TEST")
        ownerships = _db_get_ownerships("http://justatest.com")
        assert len(ownerships) == 1
        # We now create a second app for further testing.
        app2 = api.create_app("UTApp2", "translate", "{'spec':'http://justatest.com'}")
        api.add_var(app2, "spec", "http://justatest.com")

        # We transfer the ownership to the second app.
        _db_transfer_ownership("test_TEST", self.tapp, app2)

        # Verify that the ownership has indeed been transferred..
        owner = _db_get_lang_owner_app("http://justatest.com", "test_TEST")
        assert owner == app2
    def test_view_other_user_app(self):
        """
        Viewing an app that does not belong to the user SHOULD be allowed.
        """

        # Create utapp1 in utuser1
        with self.flask_app:
            rv = self.login("utuser1", "password")
            assert session["logged_in"] == True
            app = api.create_app("utapp1", "translate", '{"spec":"http://justatest.com", "bundles":{}}')
            api.add_var(app, "spec", "http://justatest.com")
            self.appid = app.unique_id

        # Login as utuser2 to check whether he can indeed view the app.
        # It SHOULD be view-able by anyone.
        rv = self.login("utuser2", "password")
        rv = self.flask_app.get("/composers/translate/selectlang?appid="+self.appid)
        assert rv.status_code == 200
        assert "utapp1" in rv.data
    def test_delete_other_user_app(self):
        """
        Deleting an app that does not belong to the user SHOULD NOT be allowed (and return a 401 error).
        """

        # Create utapp1 in utuser1
        with self.flask_app:
            rv = self.login("utuser1", "password")
            app = api.create_app("utapp1", "translate", '{"spec":"http://justatest.com"}')
            api.add_var(app, "spec", "http://justatest.com")
            self.appid = app.unique_id

        # Login as utuser2 to check whether he can indeed view the app.
        # It SHOULD be view-able by anyone.
        with self.flask_app:
            rv = self.login("utuser2", "password")
            rv = self.flask_app.post("/composers/translate/delete", data={"appid": app.unique_id, "delete": "Delete"}, follow_redirects=True)
            assert rv.status_code == 401  # Make sure deletion is NOT ALLOWED from a different user.
            app = db.session.query(App).filter_by(unique_id=self.appid)
            assert app is not None  # Make sure the app still exists.
    def test_delete_csrf_field_appears(self):
        """
        Ensure that a csrf field is added to the delete view form.
        """
        # Create utapp1 in utuser1
        with self.flask_app:
            rv = self.login("utuser1", "password")
            assert session["logged_in"] == True
            app = api.create_app("utapp1", "translate", '{"spec":"http://justatest.com", "bundles":{}}')
            api.add_var(app, "spec", "http://justatest.com")
            self.appid = app.unique_id

        # GET the app delete view with CSRF enabled.
        flask_instance.config["CSRF_ENABLED"] = True
        rv = self.flask_app.get("/composers/translate/delete?" +
                                urllib.urlencode({"appid": self.appid, "delete": "Delete"}))

        # Check whether there is indeed a _csrf_token field
        print rv.data
        assert "_csrf_token" in rv.data
        assert re.search("^.*?<input.*?hidden.*?_csrf_token.*?$", rv.data, re.MULTILINE) is not None
Exemplo n.º 23
0
def adapt_duplicate(appid):
    app = get_app(appid)
    if app is None:
        return render_template("composers/errors.html", message="Application not found")

    form = DuplicationForm()

    if form.validate_on_submit():

        # Protect against CSRF attacks.
        if not verify_csrf(request):
            return render_template("composers/errors.html",
                                   message="Request does not seem to come from the right source (csrf check)"), 400

        existing_app = get_app_by_name(form.name.data)
        if existing_app:
            if not form.name.errors:
                form.name.errors = []
            form.name.errors.append(lazy_gettext("You already have an application with this name"))
        else:
            new_app = create_app(form.name.data, 'adapt', app.spec.url, app.data)
            for appvar in app.appvars:  # Copy every appvar for the original app as well.
                add_var(new_app, appvar.name, appvar.value)

            return redirect(url_for('.adapt_edit', appid=new_app.unique_id))

    if not form.name.data:
        counter = 2
        potential_name = ''
        while counter < 1000:
            potential_name = '%s (%s)' % (app.name, counter)

            existing_app = get_app_by_name(potential_name)
            if not existing_app:
                break
            counter += 1

        form.name.data = potential_name

    return render_template("composers/adapt/duplicate.html", form=form, app=app)
Exemplo n.º 24
0
    def test_same_name_supported(self):
        api.add_var(self.tapp, "TestVar1", "TestValue1")
        api.add_var(self.tapp, "TestVar1", "TestValue2")
        api.add_var(self.tapp, "TestVar1", "TestValue3")

        vars = api.get_all_vars(self.tapp)

        assert len(vars) == 3
Exemplo n.º 25
0
    def test_same_name_supported(self):
        api.add_var(self.tapp, "TestVar1", "TestValue1")
        api.add_var(self.tapp, "TestVar1", "TestValue2")
        api.add_var(self.tapp, "TestVar1", "TestValue3")

        vars = api.get_all_vars(self.tapp)

        assert len(vars) == 3
Exemplo n.º 26
0
    def test_add_get_several_var(self):
        api.add_var(self.tapp, "TestVar1", "TestValue1")
        api.add_var(self.tapp, "TestVar2", "TestValue2")
        api.add_var(self.tapp, "TestVar3", "TestValue3")

        vars = api.get_all_vars(self.tapp)

        assert len(vars) == 3

        kvdict = {var.name: var.value for var in vars}
        assert kvdict["TestVar1"] == "TestValue1"
        assert kvdict["TestVar2"] == "TestValue2"
        assert kvdict["TestVar3"] == "TestValue3"
Exemplo n.º 27
0
    def test_add_get_several_var(self):
        api.add_var(self.tapp, "TestVar1", "TestValue1")
        api.add_var(self.tapp, "TestVar2", "TestValue2")
        api.add_var(self.tapp, "TestVar3", "TestValue3")

        vars = api.get_all_vars(self.tapp)

        assert len(vars) == 3

        kvdict = {var.name: var.value for var in vars}
        assert kvdict["TestVar1"] == "TestValue1"
        assert kvdict["TestVar2"] == "TestValue2"
        assert kvdict["TestVar3"] == "TestValue3"
Exemplo n.º 28
0
    def test_delete_var(self):
        api.add_var(self.tapp, "TestVar1", "TestValue1")
        api.add_var(self.tapp, "TestVar2", "TestValue2")
        api.add_var(self.tapp, "TestVar3", "TestValue3")

        vars = api.get_all_vars(self.tapp)

        # Find the var with the name.
        api.remove_var(next(var for var in vars if var.name == "TestVar1"))

        vars = api.get_all_vars(self.tapp)

        assert len(vars) == 2

        kvdict = {var.name: var.value for var in vars}
        assert kvdict["TestVar2"] == "TestValue2"
        assert kvdict["TestVar3"] == "TestValue3"
Exemplo n.º 29
0
    def test_delete_var(self):
        api.add_var(self.tapp, "TestVar1", "TestValue1")
        api.add_var(self.tapp, "TestVar2", "TestValue2")
        api.add_var(self.tapp, "TestVar3", "TestValue3")

        vars = api.get_all_vars(self.tapp)

        # Find the var with the name.
        api.remove_var(next(var for var in vars if var.name == "TestVar1"))

        vars = api.get_all_vars(self.tapp)

        assert len(vars) == 2

        kvdict = {var.name: var.value for var in vars}
        assert kvdict["TestVar2"] == "TestValue2"
        assert kvdict["TestVar3"] == "TestValue3"
Exemplo n.º 30
0
def translate_edit():
    """
    Translation editor for the selected language.

    @note: Returns error 400 if the source language or group don't exist.
    """

    # No matter if we are handling a GET or POST, we require these parameters.
    appid = request.values.get("appid")
    srclang = request.values.get("srclang")
    targetlang = request.values.get("targetlang")
    srcgroup = request.values.get("srcgroup")
    targetgroup = request.values.get("targetgroup")

    # Retrieve the application we want to view or edit.
    app = get_app(appid)
    if app is None:
        return render_template("composers/errors.html", message=gettext("App not found")), 404

    bm = BundleManager.create_from_existing_app(app.data)
    spec = bm.get_gadget_spec()

    # Retrieve the bundles for our lang. For this, we build the code from the info we have.
    srcbundle_code = BundleManager.partialcode_to_fullcode(srclang, srcgroup)
    targetbundle_code = BundleManager.partialcode_to_fullcode(targetlang, targetgroup)

    srcbundle = bm.get_bundle(srcbundle_code)

    # Ensure the existence of the source bundle.
    if srcbundle is None:
        return render_template("composers/errors.html",
                               message=gettext("The source language and group combination does not exist")), 400

    targetbundle = bm.get_bundle(targetbundle_code)

    # The target bundle doesn't exist yet. We need to create it ourselves.
    if targetbundle is None:
        splits = targetlang.split("_")
        if len(splits) == 2:
            lang, country = splits
            targetbundle = Bundle(lang, country, targetgroup)
            bm.add_bundle(targetbundle_code, targetbundle)

    # Get the owner for this target language.
    owner_app = _db_get_lang_owner_app(spec, targetlang)

    # If the language has no owner, we declare ourselves as owners.
    if owner_app is None:
        _db_declare_ownership(app, targetlang)
        owner_app = app

    # We override the standard Ownership's system is_owner.
    # TODO: Verify that this doesn't break anything.
    is_owner = owner_app == app

    # Get the language names
    target_translation_name = targetbundle.get_readable_name()
    source_translation_name = srcbundle.get_readable_name()

    # This is a GET request. We are essentially viewing-only.
    if request.method == "GET":
        pass

    # This is a POST request. We need to save the entries.
    else:

        # Protect against CSRF attacks.
        if not verify_csrf(request):
            return render_template("composers/errors.html",
                                   message=gettext("Request does not seem to come from the right source (csrf check)")), 400

        # Retrieve a list of all the key-values to save. That is, the parameters which start with _message_.
        messages = [(k[len("_message_"):], v) for (k, v) in request.values.items() if k.startswith("_message_")]

        # Save all the messages we retrieved from the POST or GET params into the Bundle.
        for identifier, msg in messages:
            if len(msg) > 0:  # Avoid adding empty messages.
                targetbundle.add_msg(identifier, msg)

        # Now we need to save the changes into the database.
        json_str = bm.to_json()
        update_app_data(app, json_str)

        flash(gettext("Changes have been saved."), "success")

        propose_to_owner = request.values.get("proposeToOwner")
        if propose_to_owner is not None and owner_app != app:

            # Normally we will add the proposal to the queue. However, sometimes the owner wants to auto-accept
            # all proposals. We check for this. If the autoaccept mode is enabled on the app, we do the merge
            # right here and now.
            obm = BundleManager.create_from_existing_app(owner_app.data)
            if obm.get_autoaccept():
                flash(gettext("Changes are being applied instantly because the owner has auto-accept enabled"))

                # Merge into the owner app.
                obm.merge_bundle(targetbundle_code, targetbundle)

                # Now we need to update the owner app's data. Because we aren't the owners, we can't use the appstorage
                # API directly.
                owner_app.data = obm.to_json()
                db.session.add(owner_app)
                db.session.commit()

                # [Context: We are not the leading Bundles, but our changes are merged directly into the leading Bundle]
                # We report the change to a "leading" bundle.
                on_leading_bundle_updated(spec, targetbundle)

            else:

                # We need to propose this Bundle to the owner.
                # Note: May be confusing: app.owner.login refers to the generic owner of the App, and not the owner
                # we are talking about in the specific Translate composer.
                proposal_data = {"from": app.owner.login, "timestamp": time.time(), "bundle_code": targetbundle_code,
                                 "bundle_contents": targetbundle.to_jsonable()}

                proposal_json = json.dumps(proposal_data)

                # Link the proposal with the Owner app.
                add_var(owner_app, "proposal", proposal_json)

                flash(gettext("Changes have been proposed to the owner"))

        # If we are the owner app.
        if owner_app == app:
            # [Context: We are the leading Bundle]
            # We report the change.
            on_leading_bundle_updated(spec, targetbundle)

        # Check whether the user wants to exit or to continue editing.
        if "save_exit" in request.values:
            return redirect(url_for("user.apps.index"))




    return render_template("composers/translate/edit.html", is_owner=is_owner, app=app, srcbundle=srcbundle,
                           targetbundle=targetbundle, spec=spec, target_translation_name=target_translation_name,
                           source_translation_name=source_translation_name)
Exemplo n.º 31
0
def adapt_create(adaptor_type):
    """
    adapt_create()
    Loads the form for creating new adaptor apps and the list of adaptor apps from a specific type.
    @return: The app unique id.
    """

    def build_edit_link(app):
        return url_for("adapt.adapt_edit", appid=app.unique_id)


    if adaptor_type not in ADAPTORS:
        flash("Invalid adaptor type", "error")
        return render_template('composers/adapt/create.html', apps=[], adaptor_type=adaptor_type,
                               build_edit_link=build_edit_link)

    app_plugin = ADAPTORS[adaptor_type]

    apps = appstorage.get_my_apps(adaptor_type=adaptor_type)

    # If a get request is received, we just show the new app form and the list of adaptor apps
    if request.method == "GET":
        return render_template('composers/adapt/create.html', apps=apps, adaptor_type=adaptor_type,
                               build_edit_link=build_edit_link)


    # If a post is received, we are creating an adaptor app.
    elif request.method == "POST":

        # Protect against CSRF attacks.
        if not verify_csrf(request):
            return render_template("composers/errors.html",
                                   message="Request does not seem to come from the right source (csrf check)"), 400

        # We read the app details provided by the user
        name = request.form["app_name"]
        app_description = request.form["app_description"]

        if not name:
            flash("An application name is required", "error")
            return render_template("composers/adapt/create.html", name=name, apps=apps, adaptor_type=adaptor_type,
                                   build_edit_link=build_edit_link)

        if not app_description:
            app_description = ""

        # Build the basic JSON schema of the adaptor app
        data = {
            'adaptor_version': '1',
            'name': unicode(name),
            'description': unicode(app_description),
            'adaptor_type': unicode(adaptor_type)
        }

        # Fill with the initial structure
        data.update(app_plugin['initial'])

        # URL was originally added in a later stage in case it could be changed, but not anymore.
        # TODO: The app_plugin["initial"] seems to tend to contain an url field set to NULL. This is why we
        # initialize the URL here instead of the first data initialization. This should be tidied up to be
        # less confusing.
        appurl = unicode(request.values.get("appurl"))
        data['url'] = appurl

        #Dump the contents of the previous block and check if an app with the same name exists.
        # (TODO): do we force different names even if the apps belong to another adaptor type?
        app_data = json.dumps(data)

        print "INITIAL DATA: " + app_data

        try:
            # This is where the App object itself is created.
            app = appstorage.create_app(name, 'adapt', appurl, app_data, description=app_description)
            appstorage.add_var(app, 'adaptor_type', unicode(adaptor_type))
        except appstorage.AppExistsException:
            flash("An App with that name already exists", "error")
            return render_template("composers/adapt/create.html", name=name, apps=apps, adaptor_type=adaptor_type,
                                   build_edit_link=build_edit_link)

        return redirect(url_for("adapt.adapt_edit", appid=app.unique_id))