Beispiel #1
0
def am_updatesite(annroot, userhome, options):
    """
    Update site data, leaving user data alone

    annroot     is the root directory for the Annalist software installation.
    userhome    is the home directory for the host system user issuing the command.
    options     contains options parsed from the command line.

    returns     0 if all is well, or a non-zero status code.
                This value is intended to be used as an exit status code
                for the calling program.
    """
    status       = am_errors.AM_SUCCESS
    sitesettings = am_get_site_settings(annroot, userhome, options) 
    if not sitesettings:
        print("Settings not found (%s)"%(options.configuration), file=sys.stderr)
        return am_errors.AM_NOSETTINGS
    if len(options.args) > 0:
        print(
            "Unexpected arguments for %s: (%s)"%
            (options.command, " ".join(options.args)), 
            file=sys.stderr
            )
        return am_errors.AM_UNEXPECTEDARGS
    site_layout   = layout.Layout(sitesettings.BASE_DATA_DIR, sitesettings.SITE_DIR_NAME)
    sitebasedir   = site_layout.SITE_PATH
    sitebaseurl   = "/annalist/"                # @@TODO: figure more robust way to define this
    site          = Site(sitebaseurl, site_layout.SITE_PATH)
    sitedata      = site.site_data_collection(test_exists=False)
    if sitedata is None:
        print("Initializing Annalist site metadata in %s (migrating to new layout)"%(sitebasedir))
        site = Site.create_site_metadata(
            sitebaseurl, sitebasedir,
            label="Annalist site (%s configuration)"%options.configuration, 
            description="Annalist %s site metadata and site-wide values."%options.configuration
            )
        sitedata      = site.site_data_collection()
    site_data_src = os.path.join(annroot, "annalist/data/sitedata")  # @@TODO: more robust definition
    site_data_tgt, site_data_file = sitedata._dir_path()
    # --- Migrate old site data to new site directory
    #    _annalist_site/
    site_data_old1      = os.path.join(sitebasedir, site_layout.SITEDATA_OLD_DIR1)
    old_site_metadata   = os.path.join(site_data_old1, site_layout.SITE_META_FILE)
    old_site_database   = os.path.join(site_data_old1, site_layout.SITE_DATABASE_FILE)
    old_users1          = os.path.join(site_data_old1, layout.USER_DIR_PREV)
    old_vocabs1         = os.path.join(site_data_old1, layout.VOCAB_DIR_PREV)
    if os.path.isfile(old_site_metadata):
        print("Move old site metadata: %s -> %s"%(old_site_metadata, sitebasedir))
        new_site_metadata   = os.path.join(sitebasedir, site_layout.SITE_META_FILE)
        os.rename(old_site_metadata, new_site_metadata)
    if os.path.isfile(old_site_database):
        print("Move old site database: %s -> %s"%(old_site_database, sitebasedir))
        new_site_database   = os.path.join(sitebasedir, site_layout.SITE_DATABASE_FILE)
        os.rename(old_site_database, new_site_database)
    if os.path.isdir(old_users1) or os.path.isdir(old_vocabs1):
        print("Copy Annalist old user and/or vocab data from %s"%site_data_old1)
        migrate_old_data(site_data_old1, layout.USER_DIR_PREV,  site_data_tgt, layout.USER_DIR )
        migrate_old_data(site_data_old1, layout.VOCAB_DIR_PREV, site_data_tgt, layout.VOCAB_DIR)
    #    c/_annalist_site/_annalist_collection/ - using new dir names
    site_data_old2 = os.path.join(sitebasedir, site_layout.SITEDATA_OLD_DIR2)
    old_users2     = os.path.join(site_data_old2, layout.USER_DIR)
    old_vocabs2    = os.path.join(site_data_old2, layout.VOCAB_DIR)
    if os.path.isdir(old_users2) or os.path.isdir(old_vocabs2):
        print("Copy Annalist old user and/or vocab data from %s"%site_data_old2)
        migrate_old_data(site_data_old2, layout.USER_DIR_PREV,  site_data_tgt, layout.USER_DIR )
        migrate_old_data(site_data_old2, layout.VOCAB_DIR_PREV, site_data_tgt, layout.VOCAB_DIR)
    # --- Archive old site data so it's not visible next time
    if os.path.isdir(site_data_old1):  
        archive_old_data(site_data_old1, "")
    if os.path.isdir(site_data_old2):
        archive_old_data(site_data_old2, "")
    # --- Copy latest site data to target directory
    print("Copy Annalist site data")
    print("from %s"%site_data_src)
    for sdir in layout.DATA_DIRS:
        print("- %s -> %s"%(sdir, site_data_tgt))
        Site.replace_site_data_dir(sitedata, sdir, site_data_src)
    for sdir in (layout.USER_DIR, layout.VOCAB_DIR):
        print("- %s +> %s"%(sdir, site_data_tgt))
        Site.update_site_data_dir(sitedata, sdir, site_data_src)
    for sdir in (layout.INFO_DIR,):
        print("- %s ~> %s"%(sdir, site_data_tgt))
        Site.expand_site_data_dir(sitedata, sdir, site_data_src)
    for sdir in layout.COLL_DIRS_PREV:
        remove_old_data(site_data_tgt, sdir)
    print("Generating context for site data")
    sitedata.generate_coll_jsonld_context()
    # --- Copy provider data to site config provider directory
    provider_dir_src = os.path.join(annroot, "annalist/data/identity_providers")
    provider_dir_tgt = os.path.join(sitesettings.CONFIG_BASE, "providers")
    print("Copy identity provider data:")
    print("- from: %s"%(provider_dir_src,))
    print("-   to: %s"%(provider_dir_tgt,))
    ensure_dir(provider_dir_tgt)
    updatetree(provider_dir_src, provider_dir_tgt)
    # --- Copy sample system configuration files to config directory
    config_dir_src = os.path.join(annroot, "annalist/data/config_examples")
    config_dir_tgt = os.path.join(sitesettings.CONFIG_BASE, "config")
    print("Copy system configuration sample files:")
    print("- from: %s"%(config_dir_src,))
    print("-   to: %s"%(config_dir_tgt,))
    ensure_dir(config_dir_tgt)
    updatetree(config_dir_src, provider_dir_tgt)
    return status
Beispiel #2
0
class SiteActionViewTests(AnnalistTestCase):
    """
    Tests for Site action views (completion of confirmed actions
    requested from the site view)
    """

    def setUp(self):
        init_annalist_test_site()
        self.testsite = Site(TestBaseUri, TestBaseDir)
        # self.user = User.objects.create_user('testuser', '*****@*****.**', 'testpassword')
        # self.user.save()
        # self.client = Client(HTTP_HOST=TestHost)
        # Login and permissions
        create_test_user(None, "testuser", "testpassword")
        self.client = Client(HTTP_HOST=TestHost)
        loggedin = self.client.login(username="******", password="******")
        self.assertTrue(loggedin)
        create_user_permissions(
            self.testsite.site_data_collection(), "testuser",
            user_permissions=
              [ "VIEW", "CREATE", "UPDATE", "DELETE", "CONFIG"
              , "CREATE_COLLECTION", "DELETE_COLLECTION"
              ]
            )
        return

    def tearDown(self):
        return

    @classmethod
    def setUpClass(cls):
        # Remove any collections left behind from previous tests
        resetSitedata(scope="collections")
        return

    def _conf_data(self, action="confirm"):
        action_values = (
            { 'confirm': "Confirm"
            , 'cancel':  "Cancel"
            })
        return (
            { action:             action_values[action]
            , "confirmed_action": reverse("AnnalistSiteActionView")
            , "action_params":    """{"new_label": [""], "new_id": [""], "select": ["coll1", "coll3"], "remove": ["Remove selected"]}"""
            , "cancel_action":    reverse("AnnalistSiteView")
            })

    def test_SiteActionViewTest(self):
        self.assertEqual(SiteActionView.__name__, "SiteActionView", "Check SiteActionView class name")
        return

    def test_post_confirmed_remove(self):
        # Submit positive confirmation
        u = reverse("AnnalistConfirmView")
        r = self.client.post(u, self._conf_data(action="confirm"))
        self.assertEqual(r.status_code,     302)
        self.assertEqual(r.reason_phrase,   "FOUND")
        self.assertEqual(r.content,         "")
        self.assertMatch(
            r['location'],
            "^"+TestHostUri+reverse("AnnalistSiteView")+"\\?info_head=.*&info_message=.*coll1,.*coll3.*$"
            )
        # Confirm collections deleted
        r = self.client.get(TestBasePath+"/site/")
        colls = r.context['collections']
        #@@ (diagnostic only)
        if len(colls) != len(init_collection_keys)-2:
            log.warning("@@ Collection count mismatch: %s != %d"%(len(colls), len(init_collection_keys)-2))
            log.warning("@@ Collections seen %r"%(colls.keys(),))
        #@@
        self.assertEqual(len(colls), len(init_collection_keys)-2)
        id = "coll2"
        self.assertEqual(colls[id]["annal:id"],   id)
        self.assertEqual(colls[id]["annal:url"],  init_collections[id]["annal:url"])
        self.assertEqual(colls[id]["rdfs:label"], init_collections[id]["rdfs:label"])
        return
 
    def test_post_cancelled_remove(self):
        u = reverse("AnnalistConfirmView")
        r = self.client.post(u, self._conf_data(action="cancel"))
        self.assertEqual(r.status_code,     302)
        self.assertEqual(r.reason_phrase,   "FOUND")
        self.assertEqual(r.content,         "")
        self.assertEqual(r['location'],     TestBaseUri+"/site/")
        # Confirm no collections deleted
        r = self.client.get(TestBasePath+"/site/")
        colls = r.context['collections']
        self.assertEqual(len(colls), len(init_collection_keys))
        for id in init_collections:
            self.assertEqual(colls[id]["annal:id"],   id)
            self.assertEqual(colls[id]["annal:url"],  init_collections[id]["annal:url"])
            self.assertEqual(colls[id]["rdfs:label"], init_collections[id]["rdfs:label"])
        return
def am_updatesite(annroot, userhome, options):
    """
    Update site data, leaving user data alone

    annroot     is the root directory for the Annalist software installation.
    userhome    is the home directory for the host system user issuing the command.
    options     contains options parsed from the command line.

    returns     0 if all is well, or a non-zero status code.
                This value is intended to be used as an exit status code
                for the calling program.
    """
    status = am_errors.AM_SUCCESS
    sitesettings = am_get_site_settings(annroot, userhome, options)
    if not sitesettings:
        print("Settings not found (%s)" % (options.configuration),
              file=sys.stderr)
        return am_errors.AM_NOSETTINGS
    if len(options.args) > 0:
        print("Unexpected arguments for %s: (%s)" %
              (options.command, " ".join(options.args)),
              file=sys.stderr)
        return am_errors.AM_UNEXPECTEDARGS
    site_layout = layout.Layout(sitesettings.BASE_DATA_DIR)
    sitebasedir = site_layout.SITE_PATH
    sitebaseurl = "/annalist/"  # @@TODO: figure more robust way to define this
    site = Site(sitebaseurl, site_layout.SITE_PATH)
    sitedata = site.site_data_collection(test_exists=False)
    if sitedata is None:
        print(
            "Initializing Annalist site metadata in %s (migrating to new layout)"
            % (sitebasedir))
        site = Site.create_empty_site_data(
            sitebaseurl,
            sitebasedir,
            label="Annalist site (%s configuration)" % options.configuration,
            description="Annalist %s site metadata and site-wide values." %
            options.configuration)
        sitedata = site.site_data_collection()
    site_data_src = os.path.join(
        annroot, "annalist/data/sitedata")  # @@TODO: more robust definition
    site_data_tgt, site_data_file = sitedata._dir_path()
    # --- Migrate old site data to new site directory
    site_data_old = os.path.join(sitebasedir, site_layout.SITEDATA_OLD_DIR)
    old_users = os.path.join(site_data_old, layout.USER_DIR_PREV)
    old_vocabs = os.path.join(site_data_old, layout.VOCAB_DIR_PREV)
    if os.path.isdir(old_users) or os.path.isdir(old_vocabs):
        print("Copy Annalist old user and/or vocab data from %s" %
              site_data_old)
        migrate_old_data(site_data_old, layout.USER_DIR_PREV, site_data_tgt,
                         layout.USER_DIR)
        migrate_old_data(site_data_old, layout.VOCAB_DIR_PREV, site_data_tgt,
                         layout.VOCAB_DIR)
    #@@
    # if os.path.isdir(old_users) or os.path.isdir(old_vocabs):
    #     print("Copy Annalist old user and/or vocab data from %s"%site_data_old)
    #     for sdir in ("users", "vocabs"):
    #         s     = os.path.join(site_data_old, sdir)
    #         old_s = os.path.join(site_data_old, "old_"+sdir)
    #         d     = os.path.join(site_data_tgt, sdir)
    #         if os.path.isdir(s):
    #             print("- %s +> %s (migrating)"%(sdir, d))
    #             updatetree(s, d)
    #             print("- %s >> %s (rename)"%(sdir, old_s))
    #             os.rename(s, old_s)
    #@@
    # --- Copy latest site data to target directory
    print("Copy Annalist site data")
    print("from %s" % site_data_src)
    for sdir in layout.DATA_DIRS:
        print("- %s -> %s" % (sdir, site_data_tgt))
        Site.replace_site_data_dir(sitedata, sdir, site_data_src)
    for sdir in (layout.USER_DIR, layout.VOCAB_DIR):
        print("- %s +> %s" % (sdir, site_data_tgt))
        Site.update_site_data_dir(sitedata, sdir, site_data_src)
    for sdir in layout.COLL_DIRS_PREV:
        remove_old_data(site_data_tgt, sdir)
    print("Generating %s" % (site_layout.SITEDATA_CONTEXT_DIR))
    sitedata.generate_coll_jsonld_context()
    # --- Copy provider data to site config provider directory
    provider_dir_tgt = os.path.join(sitesettings.CONFIG_BASE, "providers")
    provider_dir_src = os.path.join(annroot,
                                    "annalist/data/identity_providers")
    print("Copy identity provider data:")
    print("- from: %s" % (provider_dir_src, ))
    print("-   to: %s" % (provider_dir_tgt, ))
    updatetree(provider_dir_src, provider_dir_tgt)
    return status
class CollectionDataEditViewTest(AnnalistTestCase):
    """
    Tests for collection data edit view
    """

    def setUp(self):
        init_annalist_test_site()
        self.testsite = Site(TestBaseUri, TestBaseDir)
        self.testcoll = Collection.create(self.testsite, "testcoll", collection_create_values("testcoll"))
        # Login and permissions
        create_test_user(
            self.testsite.site_data_collection(),
            # self.testcoll, 
            "testuser", "testpassword",
            user_permissions=["VIEW", "CREATE", "UPDATE", "DELETE", "CONFIG", "ADMIN"]
            )
        self.client = Client(HTTP_HOST=TestHost)
        loggedin = self.client.login(username="******", password="******")
        self.assertTrue(loggedin)
        return

    def tearDown(self):
        resetSitedata()
        return

    #   -----------------------------------------------------------------------------
    #   Helpers
    #   -----------------------------------------------------------------------------

    def _check_collection_data_values(self, coll_id=None):
        """
        Helper function checks content of annalist collection data
        """
        self.assertTrue(Collection.exists(self.testsite, coll_id))
        t = Collection.load(self.testsite, coll_id)
        self.assertEqual(t.get_id(), coll_id)
        self.assertEqual(t.get_view_url_path(), collection_view_url(coll_id="testcoll"))
        v = collectiondata_values(coll_id=coll_id)
        self.assertDictionaryMatch(t.get_values(), v)
        return t

    #   -----------------------------------------------------------------------------
    #   Form rendering and access tests
    #   -----------------------------------------------------------------------------

    def test_get_collection_data_form_rendering(self):
        u = entitydata_edit_url("new", "_annalist_site", "_coll", view_id="Collection_view")
        r = self.client.get(u)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        field_vals = default_fields(
            coll_id="_annalist_site", 
            type_id="_coll", 
            entity_id="00000001", 
            sotware_ver=annalist.__version_data__,
            tooltip1a=context_view_field(r.context, 0, 0)['field_help'],
            tooltip1b=context_view_field(r.context, 0, 1)['field_help'],
            tooltip2 =context_view_field(r.context, 1, 0)['field_help'],
            tooltip3 =context_view_field(r.context, 2, 0)['field_help'],
            tooltip4 =context_view_field(r.context, 3, 0)['field_help'],
            tooltip5a=context_view_field(r.context, 4, 0)['field_help'],
            tooltip5b=context_view_field(r.context, 4, 1)['field_help'],
            tooltip6a=context_view_field(r.context, 5, 0)['field_help'],
            tooltip6b=context_view_field(r.context, 5, 1)['field_help'],
            tooltip7 =context_view_field(r.context, 6, 0)['field_help'],
            )
        formrow1a = """
            <div class="small-12 medium-6 columns" title="%(tooltip1a)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Id</span>
                    </div>
                    <div class="%(input_classes)s">
                        <input type="text" size="64" name="entity_id" 
                                   placeholder="(entity id)" 
                                   value="00000001" />
                    </div>
                </div>
            </div>
            """%field_vals(width=6)
        formrow1b = """
            <div class="small-12 medium-6 columns" title="%(tooltip1b)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>S/W version</span>
                    </div>
                    <div class="%(input_classes)s">
                        <span>&nbsp;</span>
                    </div>
                </div>
            </div>
            """%field_vals(width=6)            
        formrow2 = """
            <div class="small-12 columns" title="%(tooltip2)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Label</span>
                    </div>
                    <div class="%(input_classes)s">
                        <input type="text" size="64" name="Entity_label" 
                               placeholder="(label)"
                               value="" />
                    </div>
                </div>
            </div>
            """%field_vals(width=12)
        formrow3 = """
            <div class="small-12 columns" title="%(tooltip3)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Comment</span>
                    </div>
                    <div class="%(input_classes)s">
                        <textarea cols="64" rows="6" name="Entity_comment" 
                                  class="small-rows-4 medium-rows-8"
                                  placeholder="(description)"
                                  >
                        </textarea>
                    </div>
                </div>
            </div>
            """%field_vals(width=12)
        formrow4 = """
            <div class="small-12 columns" title="%(tooltip4)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Parent</span>
                    </div>
                    <div class="%(input_classes)s">
                        <select name="Coll_parent">
                            <option value="" selected="selected">(site)</option>
                            <option value="_coll/_annalist_site">Annalist data notebook test site</option>
                            <option value="_coll/coll1">Collection coll1</option>
                            <option value="_coll/coll2">Collection coll2</option>
                            <option value="_coll/coll3">Collection coll3</option>
                            <option value="_coll/testcoll">Collection testcoll</option>
                        </select>
                    </div>
                </div>
            </div>
            """%field_vals(width=12)
        formrow5a = """
             <div class="small-12 medium-6 columns" title="%(tooltip5a)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Default list</span>
                    </div>
                    <div class="%(input_classes)s">
                        <span>&nbsp;</span>
                    </div>
                </div>
            </div>
           """%field_vals(width=6)
        formrow5b = """
            <div class="small-12 medium-6 columns" title="%(tooltip5b)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Default view</span>
                    </div>
                    <div class="%(input_classes)s">
                        <span>&nbsp;</span>
                    </div>
                </div>
            </div>
            """%field_vals(width=6)            
        formrow6a = """
             <div class="small-12 medium-6 columns" title="%(tooltip6a)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Default view type</span>
                    </div>
                    <div class="%(input_classes)s">
                        <span>&nbsp;</span>
                    </div>
                </div>
            </div>
           """%field_vals(width=6)
        formrow6b = """
            <div class="small-12 medium-6 columns" title="%(tooltip6b)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Default view entity</span>
                    </div>
                    <div class="%(input_classes)s">
                        <span>&nbsp;</span>
                    </div>
                </div>
            </div>
            """%field_vals(width=6)            
        formrow7 = """
            <div class="small-12 columns" title="%(tooltip7)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Collection metadata</span>
                    </div>
                    <div class="%(input_classes)s">
                        <textarea cols="64" rows="6" name="Coll_comment" 
                                  class="small-rows-4 medium-rows-8" 
                                  placeholder="(annal:meta_comment)"
                                  >
                        </textarea>
                    </div>
                </div>
            </div>
            """%field_vals(width=12)
        # log.info(r.content)
        self.assertContains(r, formrow1a, html=True)
        self.assertContains(r, formrow1b, html=True)
        self.assertContains(r, formrow2,  html=True)
        self.assertContains(r, formrow3,  html=True)
        self.assertContains(r, formrow4,  html=True)
        self.assertContains(r, formrow5a, html=True)
        self.assertContains(r, formrow5b, html=True)
        self.assertContains(r, formrow6a, html=True)
        self.assertContains(r, formrow6b, html=True)
        self.assertContains(r, formrow7,  html=True)
        return

    # collection default view
    def test_get_default_view(self):
        u = collectiondata_url(coll_id="testcoll")
        r = self.client.get(u)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertEqual(r.context['coll_id'],          "_annalist_site")
        self.assertEqual(r.context['type_id'],          "_coll")
        self.assertEqual(r.context['entity_id'],        "testcoll")
        self.assertEqual(r.context['orig_id'],          "testcoll")
        self.assertEqual(r.context['action'],           "view")
        self.assertEqual(r.context['continuation_url'], "")
        return

    # collection default view metadata access
    def test_get_default_view_metadata(self):
        u = collectiondata_resource_url(coll_id="testcoll")
        r = self.client.get(u)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        colldata = json.loads(r.content)
        expected = (
            { "@id":                    "../"
            , "@type":                  [ "annal:Collection" ]
            , "@context":               [ {"@base": "../d/"}, "coll_context.jsonld" ]
            , "annal:id":               "testcoll"
            , "annal:type_id":          "_coll"
            , "annal:type":             "annal:Collection"
            , "rdfs:label":             "Collection testcoll"
            , "rdfs:comment":           "Description of Collection testcoll"
            , "annal:software_version": annalist.__version_data__
            })
        self.assertEqual(colldata, expected)
        return

    # collection named view context
    def test_get_named_view(self):
        u = collectiondata_view_url(coll_id="testcoll", action="view")
        r = self.client.get(u)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertEqual(r.context['coll_id'],          "_annalist_site")
        self.assertEqual(r.context['type_id'],          "_coll")
        self.assertEqual(r.context['entity_id'],        "testcoll")
        self.assertEqual(r.context['orig_id'],          "testcoll")
        self.assertEqual(r.context['action'],           "view")
        self.assertEqual(r.context['continuation_url'], "")
        return

    # collection named view edit
    def test_get_named_edit(self):
        u = collectiondata_view_url(coll_id="testcoll", action="edit")
        r = self.client.get(u)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertEqual(r.context['coll_id'],          "_annalist_site")
        self.assertEqual(r.context['type_id'],          "_coll")
        self.assertEqual(r.context['entity_id'],        "testcoll")
        self.assertEqual(r.context['orig_id'],          "testcoll")
        self.assertEqual(r.context['action'],           "edit")
        self.assertEqual(r.context['continuation_url'], "")
        return

    # collection named view edit post update
    def test_post_named_edit(self):
        u = collectiondata_view_url(coll_id="testcoll", action="edit")
        f = collectiondata_view_form_data(coll_id="testcoll", action="edit")
        r = self.client.post(u, f)
        self.assertEqual(r.status_code,   302)
        self.assertEqual(r.reason_phrase, "FOUND")
        self.assertEqual(r.content,       "")
        self.assertEqual(r['location'],   TestBaseUri+"/c/_annalist_site/d/_coll/")
        # Check updated collection data
        self._check_collection_data_values(coll_id="testcoll")
        return

    # collection named view metadata access
    def test_get_named_view_metadata(self):
        u = collectiondata_view_resource_url(coll_id="testcoll")
        r = self.client.get(u)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        colldata = json.loads(r.content)
        expected = (
            { "@id":                    "../"
            , "@type":                  [ "annal:Collection" ]
            , "@context":               [ {"@base": "../d/"}, "coll_context.jsonld" ]
            , "annal:id":               "testcoll"
            , "annal:type_id":          "_coll"
            , "annal:type":             "annal:Collection"
            , "rdfs:label":             "Collection testcoll"
            , "rdfs:comment":           "Description of Collection testcoll"
            , "annal:software_version": annalist.__version_data__
            })
        self.assertEqual(colldata, expected)
        return

    #   -----------------------------------------------------------------------------
    #   Form response tests
    #   -----------------------------------------------------------------------------

    def _no_test_post_copy_coll(self):
        # The main purpose of this test is to check that user permissions are saved properly
        self.assertFalse(CollectionData.exists(self.testcoll, "copyuser"))
        f = annalistuser_view_form_data(
            action="copy", orig_id="_default_coll_perms",
            user_id="copyuser",
            user_name="User copyuser",
            user_uri="mailto:[email protected]",
            user_permissions="VIEW CREATE UPDATE DELETE"
            )
        u = entitydata_edit_url(
            "copy", "testcoll", "_coll", entity_id="_default_coll_perms", view_id="User_view"
            )
        r = self.client.post(u, f)
        self.assertEqual(r.status_code,   302)
        self.assertEqual(r.reason_phrase, "FOUND")
        self.assertEqual(r.content,       "")
        self.assertEqual(r['location'], self.continuation_url)
        # Check that new record type exists
        self.assertTrue(CollectionData.exists(self.testcoll, "copyuser"))
        self._check_annalist_coll_values("copyuser", ["VIEW", "CREATE", "UPDATE", "DELETE"])
        return
Beispiel #5
0
class SiteViewTest(AnnalistTestCase):
    """
    Tests for Site views
    """

    def setUp(self):
        init_annalist_test_site()
        self.testsite    = Site(TestBaseUri, TestBaseDir)
        self.uri         = reverse("AnnalistSiteView")
        self.homeuri     = reverse("AnnalistHomeView")
        self.profileuri  = reverse("AnnalistProfileView")
        # Login and permissions
        create_test_user(None, "testuser", "testpassword")
        self.client = Client(HTTP_HOST=TestHost)
        loggedin = self.client.login(username="******", password="******")
        self.assertTrue(loggedin)
        create_user_permissions(
            self.testsite.site_data_collection(), "testuser",
            user_permissions=
              [ "VIEW", "CREATE", "UPDATE", "DELETE", "CONFIG"
              , "CREATE_COLLECTION", "DELETE_COLLECTION"
              ]
            )
        return

    def tearDown(self):
        return

    @classmethod
    def tearDownClass(cls):
        resetSitedata(scope="all")
        return

    def test_SiteViewTest(self):
        self.assertEqual(SiteView.__name__, "SiteView", "Check SiteView class name")
        return

    def test_get(self):
        # @@TODO: use reference to self.client, per 
        # https://docs.djangoproject.com/en/dev/topics/testing/tools/#default-test-client
        r = self.client.get(self.uri)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertContains(r, site_title("<title>%s</title>"))
        return

    def test_get_error(self):
        r = self.client.get(self.uri+"?error_head=Error&error_message=Error%20presented")
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        # self.assertEqual(r.content, "???")
        self.assertContains(r, """<h3>Error</h3>""", html=True)
        self.assertContains(r, """<p class="messages">Error presented</p>""", html=True)
        return

    def test_get_info(self):
        r = self.client.get(self.uri+"?info_head=Information&info_message=Information%20presented")
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertContains(r, """<h3>Information</h3>""", html=True)
        self.assertContains(r, """<p class="messages">Information presented</p>""", html=True)
        return

    def test_get_home(self):
        r = self.client.get(self.homeuri)
        self.assertEqual(r.status_code,   302)
        self.assertEqual(r.reason_phrase, "FOUND")
        self.assertEqual(r["location"], TestHostUri+self.uri)
        return

    def test_get_no_login(self):
        self.client.logout()
        r = self.client.get(self.uri)
        self.assertFalse(r.context["auth_create"])
        self.assertFalse(r.context["auth_update"])
        self.assertFalse(r.context["auth_delete"])
        colls = r.context['collections']
        self.assertEqual(len(colls), len(init_collection_keys))
        for id in init_collections:
            self.assertEqual(colls[id]["annal:id"],   id)
            self.assertEqual(colls[id]["annal:url"],  init_collections[id]["annal:url"])
            self.assertEqual(colls[id]["rdfs:label"], init_collections[id]["rdfs:label"])
        # Check returned HTML (checks template logic)
        # (Don't need to keep doing this as logic can be tested through context as above)
        # (See: http://stackoverflow.com/questions/2257958/)
        s = BeautifulSoup(r.content, "html.parser")
        self.assertEqual(s.html.title.string, site_title())
        homelink = s.find(class_="title-area").find(class_="name").h1.a
        self.assertEqual(homelink.string,   "Home")
        self.assertEqual(homelink['href'],  self.uri)
        menuitems = s.find(class_="top-bar-section").find(class_="right").find_all("li")
        self.assertEqualIgnoreWS(menuitems[0].a.string,  "Login")
        self.assertEqual(menuitems[0].a['href'],         self.profileuri)
        # Check displayed collections
        trows = s.form.find_all("div", class_="tbody")
        self.assertEqual(len(trows), len(init_collection_keys))
        self.assertEqual(trows[0].div.div('div')[1].a.string,  "_annalist_site")
        self.assertEqual(trows[0].div.div('div')[1].a['href'], collection_view_url("_annalist_site"))
        self.assertEqual(trows[1].div.div('div')[1].a.string,  "coll1")
        self.assertEqual(trows[1].div.div('div')[1].a['href'], collection_view_url("coll1"))
        self.assertEqual(trows[2].div.div('div')[1].a.string,  "coll2")
        self.assertEqual(trows[2].div.div('div')[1].a['href'], collection_view_url("coll2"))
        self.assertEqual(trows[3].div.div('div')[1].a.string,  "coll3")
        self.assertEqual(trows[3].div.div('div')[1].a['href'], collection_view_url("coll3"))
        return

    def test_get_with_login(self):
        r = self.client.get(self.uri)
        # Preferred way to test main view logic
        self.assertTrue(r.context["auth_create"])
        self.assertTrue(r.context["auth_update"])
        self.assertTrue(r.context["auth_delete"])
        self.assertTrue(r.context["auth_create_coll"])
        self.assertTrue(r.context["auth_delete_coll"])
        colls = r.context['collections']
        self.assertEqual(len(colls), len(init_collection_keys))
        for id in init_collections:
            # First two here added in models.site.site_data()
            self.assertEqual(colls[id]["id"],         id)
            self.assertEqual(colls[id]["url"],        init_collections[id]["annal:url"])
            self.assertEqual(colls[id]["annal:id"],   id)
            self.assertEqual(colls[id]["annal:url"],  init_collections[id]["annal:url"])
            self.assertEqual(colls[id]["rdfs:label"], init_collections[id]["rdfs:label"])
        # Check returned HTML (checks template logic)
        # (Don't need to keep doing this as logic can be tested through context as above)
        # (See: http://stackoverflow.com/questions/2257958/)
        s = BeautifulSoup(r.content, "html.parser")
        # title and top menu
        self.assertEqual(s.html.title.string, site_title())
        homelink = s.find(class_="title-area").find(class_="name").h1.a
        self.assertEqual(homelink.string,   "Home")
        self.assertEqual(homelink['href'],  self.uri)
        menuitems = s.find(class_="top-bar-section").find(class_="right").find_all("li")
        self.assertEqualIgnoreWS(menuitems[0].a.string, "User testuser")
        self.assertEqual(menuitems[0].a['href'],        TestBasePath+"/profile/")
        self.assertEqualIgnoreWS(menuitems[1].a.string, "Logout")
        self.assertEqual(menuitems[1].a['href'],        TestBasePath+"/logout/")
        # Displayed colllections and check-buttons
        # trows = s.form.find_all("div", class_="tbody")
        trows = s.select("form > div > div > div")
        self.assertEqual(len(trows), len(init_collection_keys)+4)
        site_data = (
            [ (1, "checkbox", "select", "_annalist_site")
            , (2, "checkbox", "select", "coll1")
            , (3, "checkbox", "select", "coll2")
            , (4, "checkbox", "select", "coll3")
            ])
        for i, itype, iname, ivalue in site_data:
            # tcols = trows[i].find_all("div", class_="view-value")
            tcols = trows[i].select("div > div > div")
            self.assertEqual(tcols[0].input['type'],   itype)
            self.assertEqual(tcols[0].input['name'],   iname)
            self.assertEqual(tcols[0].input['value'],  ivalue)
            self.assertEqual(tcols[1].a.string,        ivalue)
            self.assertEqual(tcols[1].a['href'],       collection_view_url(ivalue))
        # buttons to view/edit/remove selected
        btn_view = trows[5].select("div > input")[0]
        self.assertEqual(btn_view["type"],  "submit")
        self.assertEqual(btn_view["name"],  "view")
        btn_edit = trows[5].select("div > input")[1]
        self.assertEqual(btn_edit["type"],  "submit")
        self.assertEqual(btn_edit["name"],  "edit")
        btn_remove = trows[5].select("div > input")[2]
        self.assertEqual(btn_remove["type"],  "submit")
        self.assertEqual(btn_remove["name"],  "remove")
        # Input fields for new collection
        add_fields = trows[6].select("div > div > div")
        field_id    = add_fields[1].input
        field_label = add_fields[2].input
        self.assertEqual(field_id["type"],    "text")
        self.assertEqual(field_id["name"],    "new_id")
        self.assertEqual(field_label["type"], "text")
        self.assertEqual(field_label["name"], "new_label")
        # Button for new collection
        btn_new = trows[7].select("div > input")[0]
        self.assertEqual(btn_new["type"],     "submit")
        self.assertEqual(btn_new["name"],     "new")
        return

    def test_post_add(self):
        form_data = collection_new_form_data("testnew")
        r = self.client.post(self.uri, form_data)
        self.assertEqual(r.status_code,   302)
        self.assertEqual(r.reason_phrase, "FOUND")
        self.assertEqual(r.content,       "")
        self.assertEqual(r['location'],
            TestBaseUri+"/site/"
            "?info_head=Action%20completed"+
            "&info_message=Created%20new%20collection:%20'testnew'")
        # Check site now has new colllection
        r = self.client.get(self.uri)
        new_collections = init_collections.copy()
        new_collections["testnew"] = collection_values("testnew", hosturi=TestHostUri)
        colls = r.context['collections']
        for id in new_collections:
            p = "[%s]"%id
            # First two here added in model.site.site_data for view template
            self.assertEqualPrefix(colls[id]["id"],         id,                                p)
            self.assertEqualPrefix(colls[id]["url"],        new_collections[id]["annal:url"],  p)
            self.assertEqualPrefix(colls[id]["annal:id"],   id,                                p)
            self.assertEqualPrefix(colls[id]["annal:url"],  new_collections[id]["annal:url"],  p)
            self.assertEqualPrefix(colls[id]["rdfs:label"], new_collections[id]["rdfs:label"], p)
        # Check new collection has admin permissions for creator
        new_coll = Collection(self.testsite, "testnew")
        testuser_perms = new_coll.get_user_permissions("testuser", "mailto:testuser@%s"%TestHost)
        expect_perms   = ["VIEW", "CREATE", "UPDATE", "DELETE", "CONFIG", "ADMIN"]
        expect_descr   = "User testuser: permissions for Test User in collection testnew"
        self.assertEqual(testuser_perms[ANNAL.CURIE.id],                "testuser")
        self.assertEqual(testuser_perms[RDFS.CURIE.label],              "Test User")
        self.assertEqual(testuser_perms[RDFS.CURIE.comment],            expect_descr)
        self.assertEqual(testuser_perms[ANNAL.CURIE.user_uri],          "mailto:testuser@%s"%TestHost)
        self.assertEqual(testuser_perms[ANNAL.CURIE.user_permission],   expect_perms)
        return

    def test_post_remove(self):
        form_data = collection_remove_form_data(["coll1", "coll3"])
        r = self.client.post(self.uri, form_data)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertTemplateUsed(r, "annalist_confirm.html")
        # Returns confirmation form: check
        self.assertContains(r, '''<form method="POST" action="'''+TestBasePath+'''/confirm/">''', status_code=200)
        self.assertContains(r, '''<input type="submit" name="confirm" value="Confirm"/>''', html=True)
        self.assertContains(r, '''<input type="submit" name="cancel" value="Cancel"/>''', html=True)
        self.assertContains(r, '''<input type="hidden" name="confirmed_action" value="'''+reverse("AnnalistSiteActionView")+'''"/>''', html=True)
        self.assertContains(r, '''<input type="hidden" name="action_params"   value="{&quot;new_label&quot;: [&quot;&quot;], &quot;new_id&quot;: [&quot;&quot;], &quot;select&quot;: [&quot;coll1&quot;, &quot;coll3&quot;], &quot;remove&quot;: [&quot;Remove selected&quot;]}"/>''', html=True)
        self.assertContains(r, '''<input type="hidden" name="cancel_action"   value="'''+reverse("AnnalistSiteView")+'''"/>''', html=True)
        return
Beispiel #6
0
class CollectionDataEditViewTest(AnnalistTestCase):
    """
    Tests for collection data edit view
    """
    def setUp(self):
        init_annalist_test_site()
        self.testsite = Site(TestBaseUri, TestBaseDir)
        self.testcoll = Collection.create(self.testsite, "testcoll",
                                          collection_create_values("testcoll"))
        # Login and permissions
        create_test_user(
            self.testsite.site_data_collection(),
            # self.testcoll,
            "testuser",
            "testpassword",
            user_permissions=[
                "VIEW", "CREATE", "UPDATE", "DELETE", "CONFIG", "ADMIN"
            ])
        self.client = Client(HTTP_HOST=TestHost)
        loggedin = self.client.login(username="******",
                                     password="******")
        self.assertTrue(loggedin)
        return

    def tearDown(self):
        resetSitedata()
        return

    #   -----------------------------------------------------------------------------
    #   Helpers
    #   -----------------------------------------------------------------------------

    def _check_collection_data_values(self, coll_id=None):
        """
        Helper function checks content of annalist collection data
        """
        self.assertTrue(Collection.exists(self.testsite, coll_id))
        t = Collection.load(self.testsite, coll_id)
        self.assertEqual(t.get_id(), coll_id)
        self.assertEqual(t.get_view_url_path(),
                         collection_view_url(coll_id="testcoll"))
        v = collectiondata_values(coll_id=coll_id)
        self.assertDictionaryMatch(t.get_values(), v)
        return t

    #   -----------------------------------------------------------------------------
    #   Form rendering and access tests
    #   -----------------------------------------------------------------------------

    def test_get_collection_data_form_rendering(self):
        u = entitydata_edit_url("new",
                                "_annalist_site",
                                "_coll",
                                view_id="Collection_view")
        r = self.client.get(u)
        self.assertEqual(r.status_code, 200)
        self.assertEqual(r.reason_phrase, "OK")
        field_vals = default_fields(
            coll_id="_annalist_site",
            type_id="_coll",
            entity_id="00000001",
            sotware_ver=annalist.__version_data__,
            tooltip1a=context_view_field(r.context, 0, 0)['field_help'],
            tooltip1b=context_view_field(r.context, 0, 1)['field_help'],
            tooltip2=context_view_field(r.context, 1, 0)['field_help'],
            tooltip3=context_view_field(r.context, 2, 0)['field_help'],
            tooltip4=context_view_field(r.context, 3, 0)['field_help'],
            tooltip5a=context_view_field(r.context, 4, 0)['field_help'],
            tooltip5b=context_view_field(r.context, 4, 1)['field_help'],
            tooltip6a=context_view_field(r.context, 5, 0)['field_help'],
            tooltip6b=context_view_field(r.context, 5, 1)['field_help'],
            tooltip7=context_view_field(r.context, 6, 0)['field_help'],
        )
        formrow1a = """
            <div class="small-12 medium-6 columns" title="%(tooltip1a)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Id</span>
                    </div>
                    <div class="%(input_classes)s">
                        <input type="text" size="64" name="entity_id" 
                                   placeholder="(entity id)" 
                                   value="00000001" />
                    </div>
                </div>
            </div>
            """ % field_vals(width=6)
        formrow1b = """
            <div class="small-12 medium-6 columns" title="%(tooltip1b)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>S/W version</span>
                    </div>
                    <div class="%(input_classes)s">
                        <span>&nbsp;</span>
                    </div>
                </div>
            </div>
            """ % field_vals(width=6)
        formrow2 = """
            <div class="small-12 columns" title="%(tooltip2)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Label</span>
                    </div>
                    <div class="%(input_classes)s">
                        <input type="text" size="64" name="Entity_label" 
                               placeholder="(label)"
                               value="" />
                    </div>
                </div>
            </div>
            """ % field_vals(width=12)
        formrow3 = """
            <div class="small-12 columns" title="%(tooltip3)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Comment</span>
                    </div>
                    <div class="%(input_classes)s">
                        <textarea cols="64" rows="6" name="Entity_comment" 
                                  class="small-rows-4 medium-rows-8"
                                  placeholder="(description)"
                                  >
                        </textarea>
                    </div>
                </div>
            </div>
            """ % field_vals(width=12)
        formrow4 = """
            <div class="small-12 columns" title="%(tooltip4)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Parent</span>
                    </div>
                    <div class="%(input_classes)s">
                        <select name="Coll_parent">
                            <option value="" selected="selected">(site)</option>
                            <option value="_coll/_annalist_site">Annalist data notebook test site</option>
                            <option value="_coll/coll1">Collection coll1</option>
                            <option value="_coll/coll2">Collection coll2</option>
                            <option value="_coll/coll3">Collection coll3</option>
                            <option value="_coll/testcoll">Collection testcoll</option>
                        </select>
                    </div>
                </div>
            </div>
            """ % field_vals(width=12)
        formrow5a = """
             <div class="small-12 medium-6 columns" title="%(tooltip5a)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Default list</span>
                    </div>
                    <div class="%(input_classes)s">
                        <span>&nbsp;</span>
                    </div>
                </div>
            </div>
           """ % field_vals(width=6)
        formrow5b = """
            <div class="small-12 medium-6 columns" title="%(tooltip5b)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Default view</span>
                    </div>
                    <div class="%(input_classes)s">
                        <span>&nbsp;</span>
                    </div>
                </div>
            </div>
            """ % field_vals(width=6)
        formrow6a = """
             <div class="small-12 medium-6 columns" title="%(tooltip6a)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Default view type</span>
                    </div>
                    <div class="%(input_classes)s">
                        <span>&nbsp;</span>
                    </div>
                </div>
            </div>
           """ % field_vals(width=6)
        formrow6b = """
            <div class="small-12 medium-6 columns" title="%(tooltip6b)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Default view entity</span>
                    </div>
                    <div class="%(input_classes)s">
                        <span>&nbsp;</span>
                    </div>
                </div>
            </div>
            """ % field_vals(width=6)
        formrow7 = """
            <div class="small-12 columns" title="%(tooltip7)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Collection metadata</span>
                    </div>
                    <div class="%(input_classes)s">
                        <textarea cols="64" rows="6" name="Coll_comment" 
                                  class="small-rows-4 medium-rows-8" 
                                  placeholder="(annal:meta_comment)"
                                  >
                        </textarea>
                    </div>
                </div>
            </div>
            """ % field_vals(width=12)
        # log.info(r.content)
        self.assertContains(r, formrow1a, html=True)
        self.assertContains(r, formrow1b, html=True)
        self.assertContains(r, formrow2, html=True)
        self.assertContains(r, formrow3, html=True)
        self.assertContains(r, formrow4, html=True)
        self.assertContains(r, formrow5a, html=True)
        self.assertContains(r, formrow5b, html=True)
        self.assertContains(r, formrow6a, html=True)
        self.assertContains(r, formrow6b, html=True)
        self.assertContains(r, formrow7, html=True)
        return

    # collection default view
    def test_get_default_view(self):
        u = collectiondata_url(coll_id="testcoll")
        r = self.client.get(u)
        self.assertEqual(r.status_code, 200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertEqual(r.context['coll_id'], "_annalist_site")
        self.assertEqual(r.context['type_id'], "_coll")
        self.assertEqual(r.context['entity_id'], "testcoll")
        self.assertEqual(r.context['orig_id'], "testcoll")
        self.assertEqual(r.context['action'], "view")
        self.assertEqual(r.context['continuation_url'], "")
        return

    # collection default view metadata access
    def test_get_default_view_metadata(self):
        u = collectiondata_resource_url(coll_id="testcoll")
        r = self.client.get(u)
        self.assertEqual(r.status_code, 200)
        self.assertEqual(r.reason_phrase, "OK")
        colldata = json.loads(r.content)
        expected = ({
            "@id": "../",
            "@type": ["annal:Collection"],
            "@context": [{
                "@base": "../d/"
            }, "coll_context.jsonld"],
            "annal:id": "testcoll",
            "annal:type_id": "_coll",
            "annal:type": "annal:Collection",
            "rdfs:label": "Collection testcoll",
            "rdfs:comment": "Description of Collection testcoll",
            "annal:software_version": annalist.__version_data__
        })
        self.assertEqual(colldata, expected)
        return

    # collection named view context
    def test_get_named_view(self):
        u = collectiondata_view_url(coll_id="testcoll", action="view")
        r = self.client.get(u)
        self.assertEqual(r.status_code, 200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertEqual(r.context['coll_id'], "_annalist_site")
        self.assertEqual(r.context['type_id'], "_coll")
        self.assertEqual(r.context['entity_id'], "testcoll")
        self.assertEqual(r.context['orig_id'], "testcoll")
        self.assertEqual(r.context['action'], "view")
        self.assertEqual(r.context['continuation_url'], "")
        return

    # collection named view edit
    def test_get_named_edit(self):
        u = collectiondata_view_url(coll_id="testcoll", action="edit")
        r = self.client.get(u)
        self.assertEqual(r.status_code, 200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertEqual(r.context['coll_id'], "_annalist_site")
        self.assertEqual(r.context['type_id'], "_coll")
        self.assertEqual(r.context['entity_id'], "testcoll")
        self.assertEqual(r.context['orig_id'], "testcoll")
        self.assertEqual(r.context['action'], "edit")
        self.assertEqual(r.context['continuation_url'], "")
        return

    # collection named view edit post update
    def test_post_named_edit(self):
        u = collectiondata_view_url(coll_id="testcoll", action="edit")
        f = collectiondata_view_form_data(coll_id="testcoll", action="edit")
        r = self.client.post(u, f)
        self.assertEqual(r.status_code, 302)
        self.assertEqual(r.reason_phrase, "FOUND")
        self.assertEqual(r.content, "")
        self.assertEqual(r['location'],
                         TestBaseUri + "/c/_annalist_site/d/_coll/")
        # Check updated collection data
        self._check_collection_data_values(coll_id="testcoll")
        return

    # collection named view metadata access
    def test_get_named_view_metadata(self):
        u = collectiondata_view_resource_url(coll_id="testcoll")
        r = self.client.get(u)
        self.assertEqual(r.status_code, 200)
        self.assertEqual(r.reason_phrase, "OK")
        colldata = json.loads(r.content)
        expected = ({
            "@id": "../",
            "@type": ["annal:Collection"],
            "@context": [{
                "@base": "../d/"
            }, "coll_context.jsonld"],
            "annal:id": "testcoll",
            "annal:type_id": "_coll",
            "annal:type": "annal:Collection",
            "rdfs:label": "Collection testcoll",
            "rdfs:comment": "Description of Collection testcoll",
            "annal:software_version": annalist.__version_data__
        })
        self.assertEqual(colldata, expected)
        return

    #   -----------------------------------------------------------------------------
    #   Form response tests
    #   -----------------------------------------------------------------------------

    def _no_test_post_copy_coll(self):
        # The main purpose of this test is to check that user permissions are saved properly
        self.assertFalse(CollectionData.exists(self.testcoll, "copyuser"))
        f = annalistuser_view_form_data(
            action="copy",
            orig_id="_default_coll_perms",
            user_id="copyuser",
            user_name="User copyuser",
            user_uri="mailto:[email protected]",
            user_permissions="VIEW CREATE UPDATE DELETE")
        u = entitydata_edit_url("copy",
                                "testcoll",
                                "_coll",
                                entity_id="_default_coll_perms",
                                view_id="User_view")
        r = self.client.post(u, f)
        self.assertEqual(r.status_code, 302)
        self.assertEqual(r.reason_phrase, "FOUND")
        self.assertEqual(r.content, "")
        self.assertEqual(r['location'], self.continuation_url)
        # Check that new record type exists
        self.assertTrue(CollectionData.exists(self.testcoll, "copyuser"))
        self._check_annalist_coll_values(
            "copyuser", ["VIEW", "CREATE", "UPDATE", "DELETE"])
        return
Beispiel #7
0
class CollectionDataEditViewTest(AnnalistTestCase):
    """
    Tests for collection data edit view
    """

    def setUp(self):
        init_annalist_test_site()
        self.testsite = Site(TestBaseUri, TestBaseDir)
        self.testcoll = Collection.create(self.testsite, "testcoll", collection_create_values("testcoll"))
        # Login and permissions
        create_test_user(
            self.testsite.site_data_collection(),
            # self.testcoll, 
            "testuser", "testpassword",
            user_permissions=["VIEW", "CREATE", "UPDATE", "DELETE", "CONFIG", "ADMIN"]
            )
        self.client = Client(HTTP_HOST=TestHost)
        loggedin = self.client.login(username="******", password="******")
        self.assertTrue(loggedin)
        return

    def tearDown(self):
        resetSitedata(scope="all")
        return

    #   -----------------------------------------------------------------------------
    #   Helpers
    #   -----------------------------------------------------------------------------

    def _check_collection_data_values(self, coll_id=None, coll_label=None, coll_descr=None):
        """
        Helper function checks content of annalist collection data
        """
        self.assertTrue(Collection.exists(self.testsite, coll_id))
        c = Collection.load(self.testsite, coll_id)
        self.assertEqual(c.get_id(), coll_id)
        self.assertEqual(c.get_view_url_path(), collection_view_url(coll_id="testcoll"))
        v = collectiondata_values(
            coll_id=coll_id, coll_label=coll_label, coll_descr=coll_descr
            )
        self.assertDictionaryMatch(c.get_values(), v)
        return c

    def _check_annalist_user_perms(self, user_id, user_perms):
        self.assertTrue(AnnalistUser.exists(self.testcoll, user_id))
        u = AnnalistUser.load(self.testcoll, user_id)
        self.assertEqual(u.get_id(), user_id)
        self.assertEqual(u[ANNAL.CURIE.user_permission], user_perms)
        return

    #   -----------------------------------------------------------------------------
    #   Form rendering and access tests
    #   -----------------------------------------------------------------------------

    def test_get_collection_data_form_rendering(self):
        u = entitydata_edit_url("new", layout.SITEDATA_ID, layout.COLL_TYPEID, view_id="Collection_view")
        r = self.client.get(u)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        field_vals = default_fields(
            coll_id=layout.SITEDATA_ID, 
            type_id=layout.COLL_TYPEID, 
            entity_id="00000001", 
            sotware_ver=annalist.__version_data__,
            tooltip1a=context_view_field(r.context, 0, 0)['field_tooltip'],
            tooltip1b=context_view_field(r.context, 0, 1)['field_tooltip'],
            tooltip2 =context_view_field(r.context, 1, 0)['field_tooltip'],
            tooltip3 =context_view_field(r.context, 2, 0)['field_tooltip'],
            tooltip4 =context_view_field(r.context, 3, 0)['field_tooltip'],
            tooltip5a=context_view_field(r.context, 4, 0)['field_tooltip'],
            tooltip5b=context_view_field(r.context, 4, 1)['field_tooltip'],
            tooltip6a=context_view_field(r.context, 5, 0)['field_tooltip'],
            tooltip6b=context_view_field(r.context, 5, 1)['field_tooltip'],
            tooltip7 =context_view_field(r.context, 6, 0)['field_tooltip'],
            )
        formrow1a = """
            <div class="small-12 medium-6 columns" title="%(tooltip1a)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Id</span>
                    </div>
                    <div class="%(input_classes)s">
                        <input type="text" size="64" name="entity_id" 
                                   placeholder="(entity id)" 
                                   value="00000001" />
                    </div>
                </div>
            </div>
            """%field_vals(width=6)
        formrow1b = """
            <div class="small-12 medium-6 columns" title="%(tooltip1b)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>S/W version</span>
                    </div>
                    <div class="%(input_classes)s">
                        <span>&nbsp;</span>
                    </div>
                </div>
            </div>
            """%field_vals(width=6)            
        formrow2 = """
            <div class="small-12 columns" title="%(tooltip2)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Label</span>
                    </div>
                    <div class="%(input_classes)s">
                        <input type="text" size="64" name="Entity_label" 
                               placeholder="(label)"
                               value="" />
                    </div>
                </div>
            </div>
            """%field_vals(width=12)
        formrow3 = """
            <div class="small-12 columns" title="%(tooltip3)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Comment</span>
                    </div>
                    <div class="%(input_classes)s">
                        <textarea cols="64" rows="6" name="Entity_comment" 
                                  class="small-rows-4 medium-rows-8"
                                  placeholder="(description)"
                                  >
                        </textarea>
                    </div>
                </div>
            </div>
            """%field_vals(width=12)
        formrow4 = """
            <div class="small-12 columns" title="%(tooltip4)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Parent</span>
                    </div>
                    <div class="%(input_classes)s">
                        <select name="Coll_parent">
                            <option value="" selected="selected">(site)</option>
                            <option value="_coll/_annalist_site">Annalist data notebook test site</option>
                            <option value="_coll/coll1">Collection coll1</option>
                            <option value="_coll/coll2">Collection coll2</option>
                            <option value="_coll/coll3">Collection coll3</option>
                            <option value="_coll/testcoll">Collection testcoll</option>
                        </select>
                    </div>
                </div>
            </div>
            """%field_vals(width=12)
        formrow5a = """
             <div class="small-12 medium-6 columns" title="%(tooltip5a)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Default list</span>
                    </div>
                    <div class="%(input_classes)s">
                        <span>&nbsp;</span>
                    </div>
                </div>
            </div>
           """%field_vals(width=6)
        formrow5b = """
            <div class="small-12 medium-6 columns" title="%(tooltip5b)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Default view</span>
                    </div>
                    <div class="%(input_classes)s">
                        <span>&nbsp;</span>
                    </div>
                </div>
            </div>
            """%field_vals(width=6)            
        formrow6a = """
             <div class="small-12 medium-6 columns" title="%(tooltip6a)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Default view type</span>
                    </div>
                    <div class="%(input_classes)s">
                        <span>&nbsp;</span>
                    </div>
                </div>
            </div>
           """%field_vals(width=6)
        formrow6b = """
            <div class="small-12 medium-6 columns" title="%(tooltip6b)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Default view entity</span>
                    </div>
                    <div class="%(input_classes)s">
                        <span>&nbsp;</span>
                    </div>
                </div>
            </div>
            """%field_vals(width=6)            
        formrow7 = """
            <div class="small-12 columns" title="%(tooltip7)s">
                <div class="row view-value-row">
                    <div class="%(label_classes)s">
                        <span>Collection metadata</span>
                    </div>
                    <div class="%(input_classes)s">
                        <textarea cols="64" rows="6" name="Coll_comment" 
                                  class="small-rows-4 medium-rows-8" 
                                  placeholder="(annal:meta_comment)"
                                  >
                        </textarea>
                    </div>
                </div>
            </div>
            """%field_vals(width=12)
        # log.info(r.content)
        self.assertContains(r, formrow1a, html=True)
        self.assertContains(r, formrow1b, html=True)
        self.assertContains(r, formrow2,  html=True)
        self.assertContains(r, formrow3,  html=True)
        self.assertContains(r, formrow4,  html=True)
        self.assertContains(r, formrow5a, html=True)
        self.assertContains(r, formrow5b, html=True)
        self.assertContains(r, formrow6a, html=True)
        self.assertContains(r, formrow6b, html=True)
        # self.assertContains(r, formrow_viewdata, html=True)
        return

    # Collection data view
    def test_get_collection_data_view(self):
        collection_url = collection_view_url(coll_id="testcoll")
        u = collectiondata_url(coll_id="testcoll")
        r = self.client.get(u)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertEqual(r.context['coll_id'],          layout.SITEDATA_ID)
        self.assertEqual(r.context['type_id'],          layout.COLL_TYPEID)
        self.assertEqual(r.context['entity_id'],        "testcoll")
        self.assertEqual(r.context['orig_id'],          "testcoll")
        self.assertEqual(r.context['action'],           "view")
        self.assertEqual(r.context['continuation_url'], "")
        self.assertEqual(
            r.context['entity_data_ref'],      
            collection_url+layout.COLL_META_REF
            )
        self.assertEqual(
            r.context['entity_data_ref_json'], 
            collection_url+layout.COLL_META_REF+"?type=application/json"
            )
        return

    # Collection data content negotiation
    def test_get_collection_data_json(self):
        """
        Request collection data as JSON-LD
        """
        collection_url = collection_view_url(coll_id="testcoll")
        u = collectiondata_url(coll_id="testcoll")
        r = self.client.get(u, HTTP_ACCEPT="application/ld+json")
        self.assertEqual(r.status_code,   302)
        self.assertEqual(r.reason_phrase, "FOUND")
        v = r['Location']
        self.assertEqual(v, TestHostUri+collection_url+layout.COLL_META_REF)
        r = self.client.get(v)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        return

    # Collection data view metadata access
    def test_get_collection_data_view_metadata(self):
        u = collectiondata_resource_url(coll_id="testcoll")
        r = self.client.get(u)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        colldata = json.loads(r.content)
        expected = (
            { "@id":                    "../"
            , "@type":                  [ "annal:Collection" ]
            , "@context":               [ {"@base": layout.META_COLL_BASE_REF}, "coll_context.jsonld" ]
            , "annal:id":               "testcoll"
            , "annal:type_id":          layout.COLL_TYPEID
            , "annal:type":             "annal:Collection"
            , "rdfs:label":             "Collection testcoll"
            , "rdfs:comment":           "Description of Collection testcoll"
            , "annal:software_version": annalist.__version_data__
            })
        self.assertEqual(colldata, expected)
        return

    # collection named view context
    def test_get_named_view(self):
        u = collectiondata_view_url(coll_id="testcoll", action="view")
        r = self.client.get(u)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertEqual(r.context['coll_id'],          layout.SITEDATA_ID)
        self.assertEqual(r.context['type_id'],          layout.COLL_TYPEID)
        self.assertEqual(r.context['entity_id'],        "testcoll")
        self.assertEqual(r.context['orig_id'],          "testcoll")
        self.assertEqual(r.context['action'],           "view")
        self.assertEqual(r.context['continuation_url'], "")
        return

    # collection named view edit
    def test_get_named_edit(self):
        u = collectiondata_view_url(coll_id="testcoll", action="edit")
        r = self.client.get(u)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertEqual(r.context['coll_id'],          layout.SITEDATA_ID)
        self.assertEqual(r.context['type_id'],          layout.COLL_TYPEID)
        self.assertEqual(r.context['entity_id'],        "testcoll")
        self.assertEqual(r.context['orig_id'],          "testcoll")
        self.assertEqual(r.context['action'],           "edit")
        self.assertEqual(r.context['continuation_url'], "")
        return

    # collection named view edit post update
    def test_post_named_edit(self):
        u = collectiondata_view_url(coll_id="testcoll", action="edit")
        f = coll_view_form_data(coll_id="testcoll", action="edit")
        r = self.client.post(u, f)
        self.assertEqual(r.status_code,   302)
        self.assertEqual(r.reason_phrase, "FOUND")
        self.assertEqual(r.content,       "")
        self.assertEqual(r['location'],   TestBaseUri+"/c/_annalist_site/d/_coll/")
        # Check updated collection data
        self._check_collection_data_values(coll_id="testcoll")
        return

    # collection named view metadata access
    def test_get_named_view_metadata(self):
        u = collectiondata_view_resource_url(coll_id="testcoll")
        log.debug("test_get_named_view_metadata: collectiondata_view_resource_url: %s"%(u,))
        r = self.client.get(u)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        colldata = json.loads(r.content)
        expected = (
            { "@id":                    "../"
            , "@type":                  [ "annal:Collection" ]
            , "@context":               [ {"@base": layout.META_COLL_BASE_REF}, "coll_context.jsonld" ]
            , "annal:id":               "testcoll"
            , "annal:type_id":          layout.COLL_TYPEID
            , "annal:type":             "annal:Collection"
            , "rdfs:label":             "Collection testcoll"
            , "rdfs:comment":           "Description of Collection testcoll"
            , "annal:software_version": annalist.__version_data__
            })
        self.assertEqual(colldata, expected)
        return

    #   -----------------------------------------------------------------------------
    #   Form response tests
    #   -----------------------------------------------------------------------------

    def test_edit_collection_metadata(self):
        # This test performs a GET to retrieve values used in a form,
        # then a POST to save updated collection metadata.
        # This test is intended to test a problem encountered with updated 
        # entity copying logic that needs to take special account of collection
        # entities being presented as offspring of the site while being stored
        # as part of a collection.
        #
        coll_id = "testcoll"
        self.assertTrue(Collection.exists(self.testsite, coll_id))
        c = Collection.load(self.testsite, coll_id)
        self.assertEqual(c.get_id(), coll_id)
        self.assertEqual(c.get_view_url_path(), collection_view_url(coll_id="testcoll"))
        # GET collection metadata form data, and test values
        u = collectiondata_url(coll_id="testcoll")
        r = self.client.get(u)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertEqual(r.context['coll_id'],          layout.SITEDATA_ID)
        self.assertEqual(r.context['type_id'],          layout.COLL_TYPEID)
        self.assertEqual(r.context['entity_id'],        "testcoll")
        self.assertEqual(r.context['orig_id'],          "testcoll")
        self.assertEqual(r.context['orig_coll'],        layout.SITEDATA_ID)
        self.assertEqual(r.context['action'],           "view")
        self.assertEqual(r.context['continuation_url'], "")
        orig_coll = r.context['orig_coll']
        # Assemble and POST form data to =updated collection metadata
        new_label = "Updated collection metadata"
        f = coll_view_form_data(
            coll_id="testcoll", 
            action="edit", 
            coll_label=new_label,
            # orig_coll="None"
            orig_coll=layout.SITEDATA_ID
            )
        u = collectiondata_view_url(coll_id="testcoll", action="edit")
        r = self.client.post(u, f)
        self.assertEqual(r.status_code,   302)
        self.assertEqual(r.reason_phrase, "FOUND")
        self.assertEqual(r.content,       "")
        self.assertEqual(r['location'],   TestBaseUri+"/c/_annalist_site/d/_coll/")
        # Check updated collection data
        self._check_collection_data_values(coll_id="testcoll", coll_label=new_label)
        return

    def test_post_copy_user(self):
        # The main purpose of this test is to check that user permissions are 
        # saved properly
        self.assertFalse(AnnalistUser.exists(self.testcoll, "copyuser"))
        f = user_view_form_data(
            action="copy", orig_id="_default_user_perms",
            user_id="copyuser",
            user_name="User copyuser",
            user_uri="mailto:[email protected]",
            user_permissions="VIEW CREATE UPDATE DELETE",
            orig_coll=layout.SITEDATA_ID
            )
        u = entitydata_edit_url(
            "copy", "testcoll", "_user", entity_id="_default_user_perms", view_id="User_view"
            )
        r = self.client.post(u, f)
        self.assertEqual(r.status_code,   302)
        self.assertEqual(r.reason_phrase, "FOUND")
        self.assertEqual(r.content,       "")
        self.assertEqual(r['location'], TestBaseUri+"/c/testcoll/d/_user/")
        # Check that new record type exists
        self.assertTrue(AnnalistUser.exists(self.testcoll, "copyuser"))
        self._check_annalist_user_perms("copyuser", ["VIEW", "CREATE", "UPDATE", "DELETE"])
        return
Beispiel #8
0
def am_updatesite(annroot, userhome, options):
    """
    Update site data, leaving user data alone

    annroot     is the root directory for the Annalist software installation.
    userhome    is the home directory for the host system user issuing the command.
    options     contains options parsed from the command line.

    returns     0 if all is well, or a non-zero status code.
                This value is intended to be used as an exit status code
                for the calling program.
    """
    status       = am_errors.AM_SUCCESS
    sitesettings = am_get_site_settings(annroot, userhome, options) 
    if not sitesettings:
        print("Settings not found (%s)"%(options.configuration), file=sys.stderr)
        return am_errors.AM_NOSETTINGS
    if len(options.args) > 0:
        print(
            "Unexpected arguments for %s: (%s)"%
            (options.command, " ".join(options.args)), 
            file=sys.stderr
            )
        return am_errors.AM_UNEXPECTEDARGS
    site_layout   = layout.Layout(sitesettings.BASE_DATA_DIR)
    sitebasedir   = site_layout.SITE_PATH
    sitebaseurl   = "/annalist/"                # @@TODO: figure more robust way to define this
    site          = Site(sitebaseurl, site_layout.SITE_PATH)
    sitedata      = site.site_data_collection(test_exists=False)
    if sitedata is None:
        print("Initializing Annalist site metadata in %s (migrating to new layout)"%(sitebasedir))
        site = Site.create_empty_site_data(
            sitebaseurl, sitebasedir,
            label="Annalist site (%s configuration)"%options.configuration, 
            description="Annalist %s site metadata and site-wide values."%options.configuration
            )
        sitedata      = site.site_data_collection()
    site_data_src = os.path.join(annroot, "annalist/data/sitedata")  # @@TODO: more robust definition
    site_data_tgt, site_data_file = sitedata._dir_path()
    # --- Migrate old site data to new site directory
    site_data_old = os.path.join(sitebasedir, site_layout.SITEDATA_OLD_DIR)
    old_users     = os.path.join(site_data_old, layout.USER_DIR_PREV)
    old_vocabs    = os.path.join(site_data_old, layout.VOCAB_DIR_PREV)
    if os.path.isdir(old_users) or os.path.isdir(old_vocabs):
        print("Copy Annalist old user and/or vocab data from %s"%site_data_old)
        migrate_old_data(site_data_old, layout.USER_DIR_PREV,  site_data_tgt, layout.USER_DIR )
        migrate_old_data(site_data_old, layout.VOCAB_DIR_PREV, site_data_tgt, layout.VOCAB_DIR)
    #@@
    # if os.path.isdir(old_users) or os.path.isdir(old_vocabs):
    #     print("Copy Annalist old user and/or vocab data from %s"%site_data_old)
    #     for sdir in ("users", "vocabs"):
    #         s     = os.path.join(site_data_old, sdir)
    #         old_s = os.path.join(site_data_old, "old_"+sdir)
    #         d     = os.path.join(site_data_tgt, sdir)
    #         if os.path.isdir(s):
    #             print("- %s +> %s (migrating)"%(sdir, d))
    #             updatetree(s, d)
    #             print("- %s >> %s (rename)"%(sdir, old_s))
    #             os.rename(s, old_s)
    #@@
    # --- Copy latest site data to target directory
    print("Copy Annalist site data")
    print("from %s"%site_data_src)
    for sdir in layout.DATA_DIRS:
        print("- %s -> %s"%(sdir, site_data_tgt))
        Site.replace_site_data_dir(sitedata, sdir, site_data_src)
    for sdir in (layout.USER_DIR, layout.VOCAB_DIR):
        print("- %s +> %s"%(sdir, site_data_tgt))
        Site.update_site_data_dir(sitedata, sdir, site_data_src)
    for sdir in layout.COLL_DIRS_PREV:
        remove_old_data(site_data_tgt, sdir)
    print("Generating %s"%(site_layout.SITEDATA_CONTEXT_DIR))
    sitedata.generate_coll_jsonld_context()
    # --- Copy provider data to site config provider directory
    provider_dir_tgt = os.path.join(sitesettings.CONFIG_BASE, "providers")
    provider_dir_src = os.path.join(annroot, "annalist/data/identity_providers")
    print("Copy identity provider data:")
    print("- from: %s"%(provider_dir_src,))
    print("-   to: %s"%(provider_dir_tgt,))
    updatetree(provider_dir_src, provider_dir_tgt)
    return status
Beispiel #9
0
class SiteActionViewTests(AnnalistTestCase):
    """
    Tests for Site action views (completion of confirmed actions
    requested from the site view)
    """

    def setUp(self):
        init_annalist_test_site()
        self.testsite = Site(TestBaseUri, TestBaseDir)
        # self.user = User.objects.create_user('testuser', '*****@*****.**', 'testpassword')
        # self.user.save()
        # self.client = Client(HTTP_HOST=TestHost)
        # Login and permissions
        create_test_user(None, "testuser", "testpassword")
        self.client = Client(HTTP_HOST=TestHost)
        loggedin = self.client.login(username="******", password="******")
        self.assertTrue(loggedin)
        create_user_permissions(
            self.testsite.site_data_collection(), "testuser",
            user_permissions=
              [ "VIEW", "CREATE", "UPDATE", "DELETE", "CONFIG"
              , "CREATE_COLLECTION", "DELETE_COLLECTION"
              ]
            )
        return

    def tearDown(self):
        return

    @classmethod
    def setUpClass(cls):
        super(SiteActionViewTests, cls).setUpClass()
        # Remove any collections left behind from previous tests
        resetSitedata(scope="collections")
        return

    def _conf_data(self, action="confirm"):
        action_values = (
            { 'confirm': "Confirm"
            , 'cancel':  "Cancel"
            })
        return (
            { action:             action_values[action]
            , "confirmed_action": reverse("AnnalistSiteActionView")
            , "action_params":    """{"new_label": [""], "new_id": [""], "select": ["coll1", "coll3"], "remove": ["Remove selected"]}"""
            , "cancel_action":    reverse("AnnalistSiteView")
            })

    def test_SiteActionViewTest(self):
        self.assertEqual(SiteActionView.__name__, "SiteActionView", "Check SiteActionView class name")
        return

    def test_post_confirmed_remove(self):
        # Submit positive confirmation
        u = reverse("AnnalistConfirmView")
        r = self.client.post(u, self._conf_data(action="confirm"))
        self.assertEqual(r.status_code,    302)
        self.assertEqual(r.reason_phrase,  "Found")
        self.assertEqual(r.content,        b"")
        v  = reverse("AnnalistSiteView")
        e1 = "info_head="
        e2 = "info_message="
        e3 = "coll1"
        e4 = "coll3"
        self.assertIn(v,  r['location'])
        self.assertIn(e1, r['location'])
        self.assertIn(e2, r['location'])
        self.assertIn(e3, r['location'])
        self.assertIn(e4, r['location'])
        # Confirm collections deleted
        r = self.client.get(TestBasePath+"/site/")
        colls = r.context['collections']
        #@@ (diagnostic only)
        if len(colls) != len(init_collection_keys)-2:
            log.warning("@@ Collection count mismatch: %s != %d"%(len(colls), len(init_collection_keys)-2))
            log.warning("@@ Collections seen %r"%(list(colls),))
        #@@
        self.assertEqual(len(colls), len(init_collection_keys)-2)
        id = "coll2"
        self.assertEqual(colls[id]["annal:id"],   id)
        self.assertEqual(colls[id]["annal:url"],  init_collections[id]["annal:url"])
        self.assertEqual(colls[id]["rdfs:label"], init_collections[id]["rdfs:label"])
        return
 
    def test_post_cancelled_remove(self):
        u = reverse("AnnalistConfirmView")
        r = self.client.post(u, self._conf_data(action="cancel"))
        self.assertEqual(r.status_code,    302)
        self.assertEqual(r.reason_phrase,  "Found")
        self.assertEqual(r.content,        b"")
        self.assertEqual(r['location'],    TestBasePath+"/site/")
        # Confirm no collections deleted
        r = self.client.get(TestBasePath+"/site/")
        colls = r.context['collections']
        self.assertEqual(len(colls), len(init_collection_keys))
        for id in init_collections:
            self.assertEqual(colls[id]["annal:id"],   id)
            self.assertEqual(colls[id]["annal:url"],  init_collections[id]["annal:url"])
            self.assertEqual(colls[id]["rdfs:label"], init_collections[id]["rdfs:label"])
        return
Beispiel #10
0
class SiteViewTest(AnnalistTestCase):
    """
    Tests for Site views
    """

    def setUp(self):
        init_annalist_test_site()
        self.testsite    = Site(TestBaseUri, TestBaseDir)
        self.uri         = reverse("AnnalistSiteView")
        self.homeuri     = reverse("AnnalistHomeView")
        self.profileuri  = reverse("AnnalistProfileView")
        # Login and permissions
        create_test_user(None, "testuser", "testpassword")
        self.client = Client(HTTP_HOST=TestHost)
        loggedin = self.client.login(username="******", password="******")
        self.assertTrue(loggedin)
        create_user_permissions(
            self.testsite.site_data_collection(), "testuser",
            user_permissions=
              [ "VIEW", "CREATE", "UPDATE", "DELETE", "CONFIG"
              , "CREATE_COLLECTION", "DELETE_COLLECTION"
              ]
            )
        return

    def tearDown(self):
        return

    @classmethod
    def setUpClass(cls):
        super(SiteViewTest, cls).setUpClass()
        return

    @classmethod
    def tearDownClass(cls):
        super(SiteViewTest, cls).tearDownClass()
        resetSitedata(scope="all")
        return

    def test_SiteViewTest(self):
        self.assertEqual(SiteView.__name__, "SiteView", "Check SiteView class name")
        return

    def test_get(self):
        # @@TODO: use reference to self.client, per 
        # https://docs.djangoproject.com/en/dev/topics/testing/tools/#default-test-client
        r = self.client.get(self.uri)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertContains(r, site_title("<title>%s</title>"))
        return

    def test_get_error(self):
        r = self.client.get(self.uri+"?error_head=Error&error_message=Error%20presented")
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertContains(r, """<h3>Error</h3>""", html=True)
        self.assertContains(r, """<p class="messages">Error presented</p>""", html=True)
        return

    def test_get_info(self):
        r = self.client.get(self.uri+"?info_head=Information&info_message=Information%20presented")
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertContains(r, """<h3>Information</h3>""", html=True)
        self.assertContains(r, """<p class="messages">Information presented</p>""", html=True)
        return

    def test_get_home(self):
        r = self.client.get(self.homeuri)
        self.assertEqual(r.status_code,   302)
        self.assertEqual(r.reason_phrase, "Found")
        self.assertEqual(r["location"], self.uri)
        return

    def test_get_no_login(self):
        self.client.logout()
        r = self.client.get(self.uri)
        self.assertFalse(r.context["auth_create"])
        self.assertFalse(r.context["auth_update"])
        self.assertFalse(r.context["auth_delete"])
        colls = r.context['collections']
        self.assertEqual(len(colls), len(init_collection_keys))
        for id in init_collections:
            self.assertEqual(colls[id]["annal:id"],   id)
            self.assertEqual(colls[id]["annal:url"],  init_collections[id]["annal:url"])
            self.assertEqual(colls[id]["rdfs:label"], init_collections[id]["rdfs:label"])
        # Check returned HTML (checks template logic)
        # (Don't need to keep doing this as logic can be tested through context as above)
        # (See: http://stackoverflow.com/questions/2257958/)
        s = BeautifulSoup(r.content, "html.parser")
        self.assertEqual(s.html.title.string, site_title())
        homelink = s.find(class_="title-area").find(class_="name").h1.a
        self.assertEqual(homelink.string,   "Home")
        self.assertEqual(homelink['href'],  self.uri)
        menuitems = s.find(class_="top-bar-section").find(class_="right").find_all("li")
        self.assertEqualIgnoreWS(menuitems[0].a.string,  "Login")
        self.assertEqual(menuitems[0].a['href'],         self.profileuri)
        # Check displayed collections
        trows = s.form.find_all("div", class_="tbody")
        self.assertEqual(len(trows), len(init_collection_keys))
        self.assertEqual(trows[0].div.div('div')[1].a.string,  "_annalist_site")
        self.assertEqual(trows[0].div.div('div')[1].a['href'], collection_view_url("_annalist_site"))
        self.assertEqual(trows[1].div.div('div')[1].a.string,  "coll1")
        self.assertEqual(trows[1].div.div('div')[1].a['href'], collection_view_url("coll1"))
        self.assertEqual(trows[2].div.div('div')[1].a.string,  "coll2")
        self.assertEqual(trows[2].div.div('div')[1].a['href'], collection_view_url("coll2"))
        self.assertEqual(trows[3].div.div('div')[1].a.string,  "coll3")
        self.assertEqual(trows[3].div.div('div')[1].a['href'], collection_view_url("coll3"))
        return

    def test_get_with_login(self):
        r = self.client.get(self.uri)
        # Preferred way to test main view logic
        self.assertTrue(r.context["auth_create"])
        self.assertTrue(r.context["auth_update"])
        self.assertTrue(r.context["auth_delete"])
        self.assertTrue(r.context["auth_create_coll"])
        self.assertTrue(r.context["auth_delete_coll"])
        colls = r.context['collections']
        self.assertEqual(len(colls), len(init_collection_keys))
        for id in init_collections:
            # First two here added in models.site.site_data()
            self.assertEqual(colls[id]["id"],         id)
            self.assertEqual(colls[id]["url"],        init_collections[id]["annal:url"])
            self.assertEqual(colls[id]["annal:id"],   id)
            self.assertEqual(colls[id]["annal:url"],  init_collections[id]["annal:url"])
            self.assertEqual(colls[id]["rdfs:label"], init_collections[id]["rdfs:label"])
        # Check returned HTML (checks template logic)
        # (Don't need to keep doing this as logic can be tested through context as above)
        # (See: http://stackoverflow.com/questions/2257958/)
        s = BeautifulSoup(r.content, "html.parser")
        # title and top menu
        self.assertEqual(s.html.title.string, site_title())
        homelink = s.find(class_="title-area").find(class_="name").h1.a
        self.assertEqual(homelink.string,   "Home")
        self.assertEqual(homelink['href'],  self.uri)
        menuitems = s.find(class_="top-bar-section").find(class_="right").find_all("li")
        self.assertEqualIgnoreWS(menuitems[0].a.string, "User testuser")
        self.assertEqual(menuitems[0].a['href'],        TestBasePath+"/profile/")
        self.assertEqualIgnoreWS(menuitems[1].a.string, "Logout")
        self.assertEqual(menuitems[1].a['href'],        TestBasePath+"/logout/")
        # Displayed colllections and check-buttons
        # trows = s.form.find_all("div", class_="tbody")
        trows = s.select("form > div > div > div")
        self.assertEqual(len(trows), len(init_collection_keys)+4)
        site_data = (
            [ (1, "checkbox", "select", "_annalist_site")
            , (2, "checkbox", "select", "coll1")
            , (3, "checkbox", "select", "coll2")
            , (4, "checkbox", "select", "coll3")
            ])
        for i, itype, iname, ivalue in site_data:
            # tcols = trows[i].find_all("div", class_="view-value")
            tcols = trows[i].select("div > div > div")
            self.assertEqual(tcols[0].input['type'],   itype)
            self.assertEqual(tcols[0].input['name'],   iname)
            self.assertEqual(tcols[0].input['value'],  ivalue)
            self.assertEqual(tcols[1].a.string,        ivalue)
            self.assertEqual(tcols[1].a['href'],       collection_view_url(ivalue))
        # buttons to view/edit/remove selected
        btn_view = trows[5].select("div > input")[0]
        self.assertEqual(btn_view["type"],  "submit")
        self.assertEqual(btn_view["name"],  "view")
        btn_edit = trows[5].select("div > input")[1]
        self.assertEqual(btn_edit["type"],  "submit")
        self.assertEqual(btn_edit["name"],  "edit")
        btn_remove = trows[5].select("div > input")[2]
        self.assertEqual(btn_remove["type"],  "submit")
        self.assertEqual(btn_remove["name"],  "remove")
        # Input fields for new collection
        add_fields = trows[6].select("div > div > div")
        field_id    = add_fields[1].input
        field_label = add_fields[2].input
        self.assertEqual(field_id["type"],    "text")
        self.assertEqual(field_id["name"],    "new_id")
        self.assertEqual(field_label["type"], "text")
        self.assertEqual(field_label["name"], "new_label")
        # Button for new collection
        btn_new = trows[7].select("div > input")[0]
        self.assertEqual(btn_new["type"],     "submit")
        self.assertEqual(btn_new["name"],     "new")
        return

    def test_get_site_context_resource(self):
        u = reverse("AnnalistSiteResourceAccess", kwargs={"resource_ref": layout.SITE_CONTEXT_FILE})
        r = self.client.get(u)
        self.assertEqual(r.status_code,     200)
        self.assertEqual(r.reason_phrase,   "OK")
        self.assertEqual(r["content-type"], "application/ld+json")
        return

    def test_get_site_image_resource(self):
        self.testsite._ensure_values_loaded()
        self.testsite["testimage"] = (
            { "resource_name": "test-image.jpg" 
            , "resource_type": "image/jpeg"
            })
        self.testsite._save()
        u = reverse("AnnalistSiteResourceAccess", kwargs={"resource_ref": "test-image.jpg"})
        r = self.client.get(u)
        self.assertEqual(r.status_code,     200)
        self.assertEqual(r.reason_phrase,   "OK")
        self.assertEqual(r["content-type"], "image/jpeg")
        return

    def test_get_site_markdown_resource(self):
        self.testsite._ensure_values_loaded()
        self.testsite["testdatafile"] = (
            { "resource_name": "testdatafile.md" 
            , "resource_type": "text/markdown"
            })
        self.testsite._save()
        u = reverse("AnnalistSiteResourceAccess", kwargs={"resource_ref": "testdatafile.md"})
        r = self.client.get(u)
        self.assertEqual(r.status_code,     200)
        self.assertEqual(r.reason_phrase,   "OK")
        self.assertEqual(r["content-type"], "text/markdown")
        return

    def test_get_site_nonexistent_resource(self):
        self.testsite._ensure_values_loaded()
        self.testsite["nosuchfile"] = (
            { "resource_name": "nosuch.file" 
            , "resource_type": "text/plain"
            })
        self.testsite._save()
        u = reverse("AnnalistSiteResourceAccess", kwargs={"resource_ref": "nosuch.file"})
        r = self.client.get(u)
        self.assertEqual(r.status_code,     404)
        self.assertEqual(r.reason_phrase,   "Not found")
        return

    def test_post_add(self):
        form_data = collection_new_form_data("testnew")
        r = self.client.post(self.uri, form_data)
        self.assertEqual(r.status_code,   302)
        self.assertEqual(r.reason_phrase, "Found")
        self.assertEqual(r.content,       b"")
        self.assertEqual(r['location'],
            TestBasePath+"/site/"
            "?info_head=Action%20completed"+
            "&info_message=Created%20new%20collection:%20'testnew'")
        # Check site now has new colllection
        r = self.client.get(self.uri)
        new_collections = init_collections.copy()
        new_collections["testnew"] = collection_values("testnew", hosturi=TestHostUri)
        colls = r.context['collections']
        for id in new_collections:
            p = "[%s]"%id
            # First two here added in model.site.site_data for view template
            self.assertEqualPrefix(colls[id]["id"],         id,                                p)
            self.assertEqualPrefix(colls[id]["url"],        new_collections[id]["annal:url"],  p)
            self.assertEqualPrefix(colls[id]["annal:id"],   id,                                p)
            self.assertEqualPrefix(colls[id]["annal:url"],  new_collections[id]["annal:url"],  p)
            self.assertEqualPrefix(colls[id]["rdfs:label"], new_collections[id]["rdfs:label"], p)
        # Check new collection has admin permissions for creator
        new_coll = Collection(self.testsite, "testnew")
        testuser_perms = new_coll.get_user_permissions("testuser", "mailto:testuser@%s"%TestHost)
        expect_perms   = ["VIEW", "CREATE", "UPDATE", "DELETE", "CONFIG", "ADMIN"]
        expect_descr   = "User testuser: permissions for Test User in collection testnew"
        self.assertEqual(testuser_perms[ANNAL.CURIE.id],                "testuser")
        self.assertEqual(testuser_perms[RDFS.CURIE.label],              "Test User")
        self.assertEqual(testuser_perms[RDFS.CURIE.comment],            expect_descr)
        self.assertEqual(testuser_perms[ANNAL.CURIE.user_uri],          "mailto:testuser@%s"%TestHost)
        self.assertEqual(testuser_perms[ANNAL.CURIE.user_permission],   expect_perms)
        return

    def test_post_remove(self):
        form_data = collection_remove_form_data(["coll1", "coll3"])
        r = self.client.post(self.uri, form_data)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertTemplateUsed(r, "annalist_confirm.html")
        # Returns confirmation form: check
        self.assertContains(r, '''<form method="POST" action="'''+TestBasePath+'''/confirm/">''', status_code=200)
        self.assertContains(r, '''<input type="submit" name="confirm" value="Confirm"/>''', html=True)
        self.assertContains(r, '''<input type="submit" name="cancel" value="Cancel"/>''', html=True)
        self.assertContains(r, '''<input type="hidden" name="confirmed_action" value="'''+reverse("AnnalistSiteActionView")+'''"/>''', html=True)
        self.assertContains(r, '''<input type="hidden" name="cancel_action"   value="'''+reverse("AnnalistSiteView")+'''"/>''', html=True)
        self.assertHtmlContentElement(r.content,
            tagname="input", tagattrs={"name": "action_params"},
            expect_attrs=
                { "type": "hidden"
                , "value":
                    { "remove":    ["Remove selected"]
                    , "new_id":    [""]
                    , "new_label": [""]
                    , "select":    ["coll1", "coll3"]
                    }
                }
            )
        return