From 6b4329198f7659d48198049a989a1f39c813f06b Mon Sep 17 00:00:00 2001 From: Kevin McElwee Date: Tue, 1 Dec 2020 12:56:29 -0500 Subject: [PATCH 001/570] Allow django to output dbml --- cdh-web.dbml | 725 ++++++++++++++++++++++++++++++++++++++++++ cdhweb/settings.py | 1 + requirements.lock | 2 + requirements/prod.txt | 1 + 4 files changed, 729 insertions(+) create mode 100644 cdh-web.dbml diff --git a/cdh-web.dbml b/cdh-web.dbml new file mode 100644 index 000000000..75f73c1c0 --- /dev/null +++ b/cdh-web.dbml @@ -0,0 +1,725 @@ +Table auth_user_user_permissions { + user_id auto [pk] + permission_id auto [pk] +} +ref: User.id > auth_user_user_permissions.user_id +ref: Permission.id > auth_user_user_permissions.permission_id +ref: User.id > auth_user_user_permissions.user_id +ref: Permission.id > auth_user_user_permissions.permission_id + + +Table Session { + expire_date date_time [note:""] + session_data text [note:""] + session_key char [pk, unique, note:""] +} + + +Table resources_attachment_pages { + page_id auto [pk] + attachment_id auto [pk] +} +ref: Attachment.id > resources_attachment_pages.attachment_id +ref: Page.id > resources_attachment_pages.page_id + + +Table auth_group_permissions { + permission_id auto [pk] + group_id auto [pk] +} +ref: Group.id > auth_group_permissions.group_id +ref: Permission.id > auth_group_permissions.permission_id + + +Table projects_membership { + person_id auto [pk] + project_id auto [pk] +} +ref: Project.id > projects_membership.project_id +ref: Person.id > projects_membership.person_id + + +Table AssignedKeyword { + content_object None + _order None [null, note:""] + id auto [pk, unique, note:""] + keyword foreign_key [note:""] + object_pk integer [note:""] + content_type foreign_key [note:""] +} +ref: AssignedKeyword.keyword > Keyword.id +ref: AssignedKeyword.content_type > ContentType.id + + +Table projects_project_attachments { + attachment_id auto [pk] + project_id auto [pk] +} +ref: Project.id > projects_project_attachments.project_id +ref: Attachment.id > projects_project_attachments.attachment_id + + +Table Profile { + keywords_string char [note:""] + keywords None [note:""] + status integer [note:"With Draft chosen, will only be shown for admin users on the site."] + site foreign_key [note:""] + title char [note:""] + id auto [pk, unique, note:""] + institution char [note:"Institutional affiliation (for people not associated with Princeton)"] + tagged_items None [note:""] + expiry_date date_time [null, note:"With Published chosen, won't be shown after this time"] + job_title char [note:"Professional title, e.g. Professor or Assistant Professor"] + gen_description boolean [note:"If checked, the description will be automatically generated from content. Uncheck if you want to manually set a custom description."] + user one_to_one [unique, note:""] + office_location char [note:""] + education None [note:""] + department char [note:"Academic Department at Princeton or other institution (optional)"] + image file [null, note:""] + is_staff boolean [note:"CDH staff or Postdoctoral Fellow. If checked, person will be listed on the CDH staff page and will have a profile page on the site."] + created date_time [null, note:""] + _meta_title char [null, note:"Optional title to be used in the HTML title tag. If left blank, the main title field will be used."] + description text [note:""] + thumb file [null, note:""] + in_sitemap boolean [note:""] + publish_date date_time [null, note:"With Published chosen, won't be shown until this time"] + phone_number char [note:""] + pu_status char [note:""] + bio None [note:""] + short_url url [null, note:""] + tags None [null, note:"A comma-separated list of tags."] + updated date_time [null, note:""] + slug char [note:"Leave blank to have the URL auto-generated from the title."] +} +ref: Profile.site > Site.id +ref: Profile.user - Person.id + + +Table people_profile_attachments { + profile_id auto [pk] + attachment_id auto [pk] +} +ref: Profile.id > people_profile_attachments.profile_id +ref: Attachment.id > people_profile_attachments.attachment_id + + +Table ContentType { + id auto [pk, unique, note:""] + model char [note:""] + app_label char [note:""] +} + + +Table UserResource { + id auto [pk, unique, note:""] + user foreign_key [note:""] + url url [note:""] + resource_type foreign_key [note:""] +} +ref: UserResource.resource_type > ResourceType.id +ref: UserResource.user > User.id + + +Table Rating { + content_object None + user foreign_key [null, note:""] + id auto [pk, unique, note:""] + rating_date date_time [null, note:""] + value integer [note:""] + object_pk integer [note:""] + content_type foreign_key [note:""] +} +ref: Rating.content_type > ContentType.id +ref: Rating.user > User.id + + +Table User { + first_name char [note:""] + is_staff boolean [note:"Designates whether the user can log into this admin site."] + is_active boolean [note:"Designates whether this user should be treated as active. Unselect this instead of deleting accounts."] + is_superuser boolean [note:"Designates that this user has all permissions without explicitly assigning them."] + last_name char [note:""] + email email [note:""] + id auto [pk, unique, note:""] + username char [unique, note:"Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only."] + date_joined date_time [note:""] + password char [note:""] + last_login date_time [null, note:""] +} + + +Table Grant { + id auto [pk, unique, note:""] + project foreign_key [note:""] + end_date date [null, note:""] + start_date date [note:""] + grant_type foreign_key [note:""] +} +ref: Grant.project > Project.id +ref: Grant.grant_type > GrantType.id + + +Table blog_blogpost_attachments { + attachment_id auto [pk] + blogpost_id auto [pk] +} +ref: BlogPost.id > blog_blogpost_attachments.blogpost_id +ref: Attachment.id > blog_blogpost_attachments.attachment_id + + +Table blog_blogpost_users { + person_id auto [pk] + blogpost_id auto [pk] +} +ref: BlogPost.id > blog_blogpost_users.blogpost_id +ref: Person.id > blog_blogpost_users.person_id + + +Table Tag { + id auto [pk, unique, note:""] + name char [unique, note:""] + slug slug [unique, note:""] +} + + +Table Site { + id auto [pk, unique, note:""] + name char [note:""] + domain char [unique, note:""] +} + + +Table Group { + id auto [pk, unique, note:""] + name char [unique, note:""] +} + + +Table Position { + id auto [pk, unique, note:""] + user foreign_key [note:""] + end_date date [null, note:""] + start_date date [note:""] + title foreign_key [note:""] +} +ref: Position.user > User.id +ref: Position.title > Title.id + + +Table core_sitepermission_sites { + sitepermission_id auto [pk] + site_id auto [pk] +} +ref: SitePermission.id > core_sitepermission_sites.sitepermission_id +ref: Site.id > core_sitepermission_sites.site_id + + +Table ThreadedComment { + rating_sum integer [note:""] + is_public boolean [note:"Uncheck this box to make the comment effectively disappear from the site."] + by_author boolean [note:""] + site foreign_key [note:""] + id auto [pk, unique, note:""] + object_pk text [note:""] + rating None [note:""] + rating_average float [note:""] + content_type foreign_key [note:""] + comment_ptr one_to_one [pk, unique, note:""] + submit_date date_time [note:""] + user_email email [note:""] + user foreign_key [null, note:""] + user_name char [note:""] + user_url url [note:""] + content_object None + comment text [note:""] + replied_to foreign_key [null, note:""] + ip_address generic_ip_address [null, note:""] + is_removed boolean [note:"Check this box if the comment is inappropriate. A "This comment has been removed" message will be displayed instead."] + rating_count integer [note:""] +} +ref: ThreadedComment.content_type > ContentType.id +ref: ThreadedComment.site > Site.id +ref: ThreadedComment.user > User.id +ref: ThreadedComment.comment_ptr - Comment.id +ref: ThreadedComment.replied_to > ThreadedComment.comment_ptr + + +Table Comment { + is_public boolean [note:"Uncheck this box to make the comment effectively disappear from the site."] + content_object None + site foreign_key [note:""] + id auto [pk, unique, note:""] + object_pk text [note:""] + content_type foreign_key [note:""] + submit_date date_time [note:""] + user_email email [note:""] + user foreign_key [null, note:""] + user_name char [note:""] + user_url url [note:""] + comment text [note:""] + ip_address generic_ip_address [null, note:""] + is_removed boolean [note:"Check this box if the comment is inappropriate. A "This comment has been removed" message will be displayed instead."] +} +ref: Comment.content_type > ContentType.id +ref: Comment.site > Site.id +ref: Comment.user > User.id + + +Table LogEntry { + object_id text [null, note:""] + user foreign_key [note:""] + action_flag positive_small_integer [note:""] + change_message text [note:""] + id auto [pk, unique, note:""] + action_time date_time [note:""] + object_repr char [note:""] + content_type foreign_key [null, note:""] +} +ref: LogEntry.user > User.id +ref: LogEntry.content_type > ContentType.id + + +Table Keyword { + id auto [pk, unique, note:""] + slug char [note:"Leave blank to have the URL auto-generated from the title."] + site foreign_key [note:""] + title char [note:""] +} +ref: Keyword.site > Site.id + + +Table Link { + keywords_string char [note:""] + status integer [note:"With Draft chosen, will only be shown for admin users on the site."] + site foreign_key [note:""] + title char [note:""] + id auto [pk, unique, note:""] + content_model char [null, note:""] + expiry_date date_time [null, note:"With Published chosen, won't be shown after this time"] + keywords None [note:""] + gen_description boolean [note:"If checked, the description will be automatically generated from content. Uncheck if you want to manually set a custom description."] + _order None [null, note:""] + created date_time [null, note:""] + parent foreign_key [null, note:""] + _meta_title char [null, note:"Optional title to be used in the HTML title tag. If left blank, the main title field will be used."] + description text [note:""] + slug char [note:"Leave blank to have the URL auto-generated from the title."] + in_sitemap boolean [note:""] + publish_date date_time [null, note:"With Published chosen, won't be shown until this time"] + page_ptr one_to_one [pk, unique, note:""] + in_menus None [null, note:""] + short_url url [null, note:""] + titles char [null, note:""] + updated date_time [null, note:""] + login_required boolean [note:"If checked, only logged in users can view this page"] +} +ref: Link.site > Site.id +ref: Link.parent > Page.id +ref: Link.page_ptr - Page.id + + +Table Title { + id auto [pk, unique, note:""] + sort_order positive_integer [note:""] + title char [unique, note:""] +} + + +Table events_event_speakers { + event_id auto [pk] + person_id auto [pk] +} +ref: Event.id > events_event_speakers.event_id +ref: Person.id > events_event_speakers.person_id + + +Table Permission { + id auto [pk, unique, note:""] + name char [note:""] + codename char [note:""] + content_type foreign_key [note:""] +} +ref: Permission.content_type > ContentType.id + + +Table Redirect { + id auto [pk, unique, note:""] + new_path char [note:"This can be either an absolute path (as above) or a full URL starting with 'http://'."] + old_path char [note:"This should be an absolute path, excluding the domain name. Example: '/events/search/'."] + site foreign_key [note:""] +} +ref: Redirect.site > Site.id + + +Table events_event_attachments { + event_id auto [pk] + attachment_id auto [pk] +} +ref: Event.id > events_event_attachments.event_id +ref: Attachment.id > events_event_attachments.attachment_id + + +Table RichTextPage { + keywords_string char [note:""] + status integer [note:"With Draft chosen, will only be shown for admin users on the site."] + site foreign_key [note:""] + title char [note:""] + id auto [pk, unique, note:""] + content_model char [null, note:""] + expiry_date date_time [null, note:"With Published chosen, won't be shown after this time"] + keywords None [note:""] + gen_description boolean [note:"If checked, the description will be automatically generated from content. Uncheck if you want to manually set a custom description."] + _order None [null, note:""] + created date_time [null, note:""] + content None [note:""] + parent foreign_key [null, note:""] + _meta_title char [null, note:"Optional title to be used in the HTML title tag. If left blank, the main title field will be used."] + description text [note:""] + slug char [note:"Leave blank to have the URL auto-generated from the title."] + in_sitemap boolean [note:""] + publish_date date_time [null, note:"With Published chosen, won't be shown until this time"] + page_ptr one_to_one [pk, unique, note:""] + in_menus None [null, note:""] + short_url url [null, note:""] + titles char [null, note:""] + updated date_time [null, note:""] + login_required boolean [note:"If checked, only logged in users can view this page"] +} +ref: RichTextPage.site > Site.id +ref: RichTextPage.parent > Page.id +ref: RichTextPage.page_ptr - Page.id + + +Table Event { + keywords_string char [note:""] + status integer [note:"With Draft chosen, will only be shown for admin users on the site."] + location foreign_key [null, note:""] + site foreign_key [note:""] + title char [note:""] + id auto [pk, unique, note:""] + event_type foreign_key [note:""] + join_url url [null, note:"Join URL for virtual events, e.g. Zoom meetings."] + expiry_date date_time [null, note:"With Published chosen, won't be shown after this time"] + keywords None [note:""] + gen_description boolean [note:"If checked, the description will be automatically generated from content. Uncheck if you want to manually set a custom description."] + created date_time [null, note:""] + content None [note:""] + image file [null, note:"Image for display on event detail page (optional)"] + end_time date_time [note:""] + _meta_title char [null, note:"Optional title to be used in the HTML title tag. If left blank, the main title field will be used."] + description text [note:""] + thumb file [null, note:"Image for display on event card (optional)"] + in_sitemap boolean [note:""] + publish_date date_time [null, note:"With Published chosen, won't be shown until this time"] + sponsor char [null, note:""] + start_time date_time [note:""] + tagged_items None [note:""] + short_url url [null, note:""] + tags None [null, note:"A comma-separated list of tags."] + attendance positive_integer [null, note:"Total number of people who attended the event. (Internal only, for reporting purposes.)"] + updated date_time [null, note:""] + slug char [note:"Leave blank to have the URL auto-generated from the title."] +} +ref: Event.site > Site.id +ref: Event.location > Location.id +ref: Event.event_type > EventType.id + + +Table Person { + first_name char [note:""] + is_staff boolean [note:"Designates whether the user can log into this admin site."] + is_active boolean [note:"Designates whether this user should be treated as active. Unselect this instead of deleting accounts."] + is_superuser boolean [note:"Designates that this user has all permissions without explicitly assigning them."] + last_name char [note:""] + email email [note:""] + id auto [pk, unique, note:""] + username char [unique, note:"Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only."] + date_joined date_time [note:""] + password char [note:""] + last_login date_time [null, note:""] +} + + +Table ProjectResource { + id auto [pk, unique, note:""] + project foreign_key [note:""] + url url [note:""] + resource_type foreign_key [note:""] +} +ref: ProjectResource.resource_type > ResourceType.id +ref: ProjectResource.project > Project.id + + +Table blog_blogpost_related_posts { + to_blogpost_id auto [pk] + from_blogpost_id auto [pk] +} +ref: BlogPost.id > blog_blogpost_related_posts.from_blogpost_id +ref: BlogPost.id > blog_blogpost_related_posts.to_blogpost_id + + +Table auth_user_groups { + user_id auto [pk] + group_id auto [pk] +} +ref: User.id > auth_user_groups.user_id +ref: Group.id > auth_user_groups.group_id +ref: User.id > auth_user_groups.user_id +ref: Group.id > auth_user_groups.group_id + + +Table Page { + keywords_string char [note:""] + status integer [note:"With Draft chosen, will only be shown for admin users on the site."] + site foreign_key [note:""] + title char [note:""] + id auto [pk, unique, note:""] + content_model char [null, note:""] + expiry_date date_time [null, note:"With Published chosen, won't be shown after this time"] + keywords None [note:""] + gen_description boolean [note:"If checked, the description will be automatically generated from content. Uncheck if you want to manually set a custom description."] + _order None [null, note:""] + created date_time [null, note:""] + parent foreign_key [null, note:""] + _meta_title char [null, note:"Optional title to be used in the HTML title tag. If left blank, the main title field will be used."] + description text [note:""] + slug char [note:"Leave blank to have the URL auto-generated from the title."] + in_sitemap boolean [note:""] + publish_date date_time [null, note:"With Published chosen, won't be shown until this time"] + in_menus None [null, note:""] + short_url url [null, note:""] + titles char [null, note:""] + updated date_time [null, note:""] + login_required boolean [note:"If checked, only logged in users can view this page"] +} +ref: Page.site > Site.id +ref: Page.parent > Page.id + + +Table SessionTicket { + id auto [pk, unique, note:""] + ticket char [note:""] + session_key char [note:""] +} + + +Table LandingPage { + keywords_string char [note:""] + status integer [note:"With Draft chosen, will only be shown for admin users on the site."] + site foreign_key [note:""] + title char [note:""] + id auto [pk, unique, note:""] + content_model char [null, note:""] + expiry_date date_time [null, note:"With Published chosen, won't be shown after this time"] + keywords None [note:""] + gen_description boolean [note:"If checked, the description will be automatically generated from content. Uncheck if you want to manually set a custom description."] + _order None [null, note:""] + created date_time [null, note:""] + content None [note:""] + parent foreign_key [null, note:""] + tagline char [note:""] + _meta_title char [null, note:"Optional title to be used in the HTML title tag. If left blank, the main title field will be used."] + description text [note:""] + slug char [note:"Leave blank to have the URL auto-generated from the title."] + in_sitemap boolean [note:""] + publish_date date_time [null, note:"With Published chosen, won't be shown until this time"] + page_ptr one_to_one [pk, unique, note:""] + image file [null, note:""] + in_menus None [null, note:""] + short_url url [null, note:""] + titles char [null, note:""] + updated date_time [null, note:""] + login_required boolean [note:"If checked, only logged in users can view this page"] +} +ref: LandingPage.site > Site.id +ref: LandingPage.parent > Page.id +ref: LandingPage.page_ptr - Page.id + + +Table Role { + id auto [pk, unique, note:""] + sort_order positive_integer [note:""] + title char [unique, note:""] +} + + +Table SitePermission { + id auto [pk, unique, note:""] + user one_to_one [unique, note:""] +} +ref: SitePermission.user - User.id + + +Table ResourceType { + id auto [pk, unique, note:""] + name char [note:""] + sort_order positive_integer [note:""] +} + + +Table Attachment { + author char [note:""] + title char [note:""] + id auto [pk, unique, note:""] + attachment_type char [note:""] + url url [note:""] + file file [note:""] +} + + +Table BlogPost { + short_url url [null, note:""] + status integer [note:"With Draft chosen, will only be shown for admin users on the site."] + _meta_title char [null, note:"Optional title to be used in the HTML title tag. If left blank, the main title field will be used."] + site foreign_key [note:""] + title char [note:""] + id auto [pk, unique, note:""] + in_sitemap boolean [note:""] + description text [note:""] + publish_date date_time [null, note:"With Published chosen, won't be shown until this time"] + tagged_items None [note:""] + is_featured boolean [note:"Feature the post in the carousel on the homepage."] + expiry_date date_time [null, note:"With Published chosen, won't be shown after this time"] + keywords None [note:""] + gen_description boolean [note:"If checked, the description will be automatically generated from content. Uncheck if you want to manually set a custom description."] + slug char [note:"Leave blank to have the URL auto-generated from the title."] + featured_image file [null, note:"Appears on the homepage carousel when post is featured."] + created date_time [null, note:""] + content None [note:""] + tags None [null, note:"A comma-separated list of tags."] + updated date_time [null, note:""] + keywords_string char [note:""] +} +ref: BlogPost.site > Site.id + + +Table TaggedItem { + id auto [pk, unique, note:""] + object_id integer [note:""] + tag foreign_key [note:""] + content_object None + content_type foreign_key [note:""] +} +ref: TaggedItem.tag > Tag.id +ref: TaggedItem.content_type > ContentType.id + + +Table Membership { + project foreign_key [note:""] + role foreign_key [note:""] + person foreign_key [note:""] + id auto [pk, unique, note:""] + end_date date [null, note:""] + start_date date [note:""] +} +ref: Membership.project > Project.id +ref: Membership.person > Person.id +ref: Membership.role > Role.id + + +Table GrantType { + id auto [pk, unique, note:""] + grant_type char [unique, note:""] +} + + +Table Location { + id auto [pk, unique, note:""] + address char [null, note:"Address of the location (will not display if same as name)"] + name char [note:"Name of the location"] + is_virtual boolean [note:"Virtual platforms, i.e. Zoom or Google Hangouts"] + short_name char [note:""] +} + + +Table EventType { + id auto [pk, unique, note:""] + name char [unique, note:""] +} + + +Table ProxyGrantingTicket { + user foreign_key [null, note:""] + session_key char [null, note:""] + pgtiou char [null, note:""] + id auto [pk, unique, note:""] + date date_time [note:""] + pgt char [null, note:""] +} +ref: ProxyGrantingTicket.user > User.id + + +Table projects_projectresource { + project_id auto [pk] + resource_type_id auto [pk] +} +ref: Project.id > projects_projectresource.project_id +ref: ResourceType.id > projects_projectresource.resource_type_id + + +Table CommentFlag { + id auto [pk, unique, note:""] + flag char [note:""] + comment foreign_key [note:""] + flag_date date_time [note:""] + user foreign_key [note:""] +} +ref: CommentFlag.user > User.id +ref: CommentFlag.comment > Comment.id + + +Table Project { + keywords_string char [note:""] + status integer [note:"With Draft chosen, will only be shown for admin users on the site."] + site foreign_key [note:""] + title char [note:""] + id auto [pk, unique, note:""] + tagged_items None [note:""] + expiry_date date_time [null, note:"With Published chosen, won't be shown after this time"] + keywords None [note:""] + gen_description boolean [note:"If checked, the description will be automatically generated from content. Uncheck if you want to manually set a custom description."] + long_description None [note:""] + working_group boolean [note:"Project is a long-term collaborative group associated with the CDH."] + created date_time [null, note:""] + _meta_title char [null, note:"Optional title to be used in the HTML title tag. If left blank, the main title field will be used."] + description text [note:""] + thumb file [null, note:""] + slug char [note:"Leave blank to have the URL auto-generated from the title."] + in_sitemap boolean [note:""] + publish_date date_time [null, note:"With Published chosen, won't be shown until this time"] + image file [null, note:""] + short_url url [null, note:""] + tags None [null, note:"A comma-separated list of tags."] + short_description char [note:"Brief tagline for display on project card in browse view"] + cdh_built boolean [note:"Project built by CDH Development & Design team."] + updated date_time [null, note:""] + highlight boolean [note:"Include in randomized project display on the home page."] +} +ref: Project.site > Site.id + + +Table people_position { + user_id auto [pk] + title_id auto [pk] +} +ref: Title.id > people_position.title_id +ref: User.id > people_position.user_id + + +Table Setting { + id auto [pk, unique, note:""] + name char [note:""] + site foreign_key [note:""] + value char [note:""] +} +ref: Setting.site > Site.id + + +Table resources_userresource { + user_id auto [pk] + resource_type_id auto [pk] +} +ref: ResourceType.id > resources_userresource.resource_type_id +ref: User.id > resources_userresource.user_id + + diff --git a/cdhweb/settings.py b/cdhweb/settings.py index 6fb1fdb8b..59a406e1d 100644 --- a/cdhweb/settings.py +++ b/cdhweb/settings.py @@ -322,6 +322,7 @@ "fullurl", "django_cas_ng", "pucas", + "django_dbml", # local apps "cdhweb.projects", "cdhweb.people", diff --git a/requirements.lock b/requirements.lock index 5b720a4ab..91bd53d59 100644 --- a/requirements.lock +++ b/requirements.lock @@ -17,6 +17,7 @@ django-cas-ng==4.1.1 django-compressor==2.4 django-compressor-autoprefixer==0.1.0 django-contrib-comments==1.9.2 +django-dbml==0.3.5 django-debug-toolbar==3.1.1 django-fullurl==1.1 django-taggit==1.3.0 @@ -29,6 +30,7 @@ idna==2.10 imagesize==1.2.0 importlib-metadata==2.0.0 iniconfig==1.1.1 +install==1.3.4 Jinja2==2.11.2 ldap3==2.8.1 lxml==4.6.1 diff --git a/requirements/prod.txt b/requirements/prod.txt index 12aa9e5bd..dc940f8b1 100644 --- a/requirements/prod.txt +++ b/requirements/prod.txt @@ -16,3 +16,4 @@ icalendar attrdict django-fullurl django-apptemplates +django-dbml \ No newline at end of file From c0cb118e2d42da9549836f81114e365e67f4f510 Mon Sep 17 00:00:00 2001 From: Kevin McElwee Date: Tue, 1 Dec 2020 13:00:33 -0500 Subject: [PATCH 002/570] Remove duplicates and quotes to prevent dbdocs syntax errors --- cdh-web.dbml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/cdh-web.dbml b/cdh-web.dbml index 75f73c1c0..66919d826 100644 --- a/cdh-web.dbml +++ b/cdh-web.dbml @@ -4,9 +4,6 @@ Table auth_user_user_permissions { } ref: User.id > auth_user_user_permissions.user_id ref: Permission.id > auth_user_user_permissions.permission_id -ref: User.id > auth_user_user_permissions.user_id -ref: Permission.id > auth_user_user_permissions.permission_id - Table Session { expire_date date_time [note:""] @@ -234,7 +231,7 @@ Table ThreadedComment { comment text [note:""] replied_to foreign_key [null, note:""] ip_address generic_ip_address [null, note:""] - is_removed boolean [note:"Check this box if the comment is inappropriate. A "This comment has been removed" message will be displayed instead."] + is_removed boolean [note:"Check this box if the comment is inappropriate. A *This comment has been removed* message will be displayed instead."] rating_count integer [note:""] } ref: ThreadedComment.content_type > ContentType.id @@ -258,7 +255,7 @@ Table Comment { user_url url [note:""] comment text [note:""] ip_address generic_ip_address [null, note:""] - is_removed boolean [note:"Check this box if the comment is inappropriate. A "This comment has been removed" message will be displayed instead."] + is_removed boolean [note:"Check this box if the comment is inappropriate. A *This comment has been removed* message will be displayed instead."] } ref: Comment.content_type > ContentType.id ref: Comment.site > Site.id @@ -464,8 +461,6 @@ Table auth_user_groups { } ref: User.id > auth_user_groups.user_id ref: Group.id > auth_user_groups.group_id -ref: User.id > auth_user_groups.user_id -ref: Group.id > auth_user_groups.group_id Table Page { From 472a50b3f4a3c63935545fb177868a81277efe4b Mon Sep 17 00:00:00 2001 From: Kevin McElwee Date: Mon, 14 Dec 2020 15:04:13 -0500 Subject: [PATCH 003/570] Add github actions dbdocs draft --- .github/workflows/unit_tests.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 8641f1b97..fb4af4dd5 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -82,6 +82,17 @@ jobs: run: py.test --cov=./ --cov-report=xml - name: Upload test coverage to Codecov uses: codecov/codecov-action@v1 + + # Build and publish dbdocs + - name: Download dbdocs + run: npm install dbdocs # remove me + - name: Generate DBML + run: python manage.py dbml > cdh-web.dbml + - name: Login to dbdocs + run: echo ${{ secrets.KEVIN_DBDOCS_KEY }} | dbdocs login + - name: Push to dbdocs + run: dbdocs build cdh-web.dbml + # Send a message to slack to report the build status. The webhook is stored # at the organization level and available to all repositories. Only run on # scheduled builds & pushes, since PRs automatically report to Slack. From ea909074b6b88a980c2e9bd4f6fa8ab428f28aca Mon Sep 17 00:00:00 2001 From: Kevin McElwee Date: Mon, 14 Dec 2020 15:05:45 -0500 Subject: [PATCH 004/570] Add project to dbdocs command line --- .github/workflows/unit_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index fb4af4dd5..3c08d7b70 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -91,7 +91,7 @@ jobs: - name: Login to dbdocs run: echo ${{ secrets.KEVIN_DBDOCS_KEY }} | dbdocs login - name: Push to dbdocs - run: dbdocs build cdh-web.dbml + run: dbdocs build cdh-web.dbml --project cdh-web-gh-actions # Send a message to slack to report the build status. The webhook is stored # at the organization level and available to all repositories. Only run on From 56782403729147e92e1014b801073582f931f4f4 Mon Sep 17 00:00:00 2001 From: Kevin McElwee Date: Mon, 14 Dec 2020 15:08:44 -0500 Subject: [PATCH 005/570] Install dbdocs globally --- .github/workflows/unit_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 3c08d7b70..70b71cf0c 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -85,7 +85,7 @@ jobs: # Build and publish dbdocs - name: Download dbdocs - run: npm install dbdocs # remove me + run: npm install -g dbdocs # remove me - name: Generate DBML run: python manage.py dbml > cdh-web.dbml - name: Login to dbdocs From 4b0ea90303f58927a6ef8c471c49f95638bea849 Mon Sep 17 00:00:00 2001 From: Kevin McElwee Date: Mon, 14 Dec 2020 15:30:07 -0500 Subject: [PATCH 006/570] Update dbdocs actions --- .github/workflows/unit_tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 70b71cf0c..7e4b06ad5 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -85,13 +85,13 @@ jobs: # Build and publish dbdocs - name: Download dbdocs - run: npm install -g dbdocs # remove me + run: npm install -g dbdocs - name: Generate DBML run: python manage.py dbml > cdh-web.dbml - name: Login to dbdocs - run: echo ${{ secrets.KEVIN_DBDOCS_KEY }} | dbdocs login + run: echo ${{ secrets.DBDOCS_KEY }} | dbdocs login - name: Push to dbdocs - run: dbdocs build cdh-web.dbml --project cdh-web-gh-actions + run: dbdocs build cdh-web.dbml --project cdh-web # Send a message to slack to report the build status. The webhook is stored # at the organization level and available to all repositories. Only run on From 89b9077b6233484d108e81584375e2cc97fb9cfa Mon Sep 17 00:00:00 2001 From: Kevin McElwee Date: Mon, 14 Dec 2020 16:02:23 -0500 Subject: [PATCH 007/570] Update requirements.lock with new django-dbml --- requirements.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.lock b/requirements.lock index 91bd53d59..42626ea02 100644 --- a/requirements.lock +++ b/requirements.lock @@ -17,7 +17,7 @@ django-cas-ng==4.1.1 django-compressor==2.4 django-compressor-autoprefixer==0.1.0 django-contrib-comments==1.9.2 -django-dbml==0.3.5 +django-dbml==0.4.0 django-debug-toolbar==3.1.1 django-fullurl==1.1 django-taggit==1.3.0 From c46f935f3aeb7ac72f9edcf537e0894fcbb000e2 Mon Sep 17 00:00:00 2001 From: Kevin McElwee Date: Mon, 14 Dec 2020 16:06:32 -0500 Subject: [PATCH 008/570] Update readme with dbdocs --- README.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.rst b/README.rst index db1c70cda..44d95419d 100644 --- a/README.rst +++ b/README.rst @@ -109,6 +109,11 @@ directory:: When building documentation for a production release, use `make docs` to update the published documentation on GitHub Pages. +On every commit, GitHub Actions will generate and then publish a database diagram to `dbdocs @ princetoncdh/cdh-web `_. But to generate locally, install and log into dbdocs. Then run:: + + python manage.py dbml > cdh-web.dbml + dbdocs build cdh-web.dbml --project cdh-web + License ------- This project is licensed under the `Apache 2.0 License `_. From 6b4a9e7ed3e16506672aee74550103866e58714e Mon Sep 17 00:00:00 2001 From: Nick Budak Date: Mon, 6 Jan 2020 15:35:46 -0500 Subject: [PATCH 009/570] Install and configure wagtail - Add wagtail-specific settings to settings.py - Update templates to use wagtail tags - Update urlconf to add wagtail URLs - Add wagtail user bar to base template See #183 --- cdhweb/local_settings.py.sample | 5 ++ cdhweb/settings.py | 41 +++++++++++++---- cdhweb/urls.py | 76 ++++++++++++++++--------------- requirements/prod.txt | 2 + templates/base.html | 6 +-- templates/wagtailadmin/base.html | 7 +++ templates/wagtailadmin/login.html | 11 +++++ 7 files changed, 99 insertions(+), 49 deletions(-) create mode 100644 templates/wagtailadmin/base.html create mode 100644 templates/wagtailadmin/login.html diff --git a/cdhweb/local_settings.py.sample b/cdhweb/local_settings.py.sample index 7193eba9b..f601e51fa 100644 --- a/cdhweb/local_settings.py.sample +++ b/cdhweb/local_settings.py.sample @@ -91,6 +91,11 @@ PUCAS_LDAP.update({ # }, # } +# Wagtail sends email notifications when content is submitted for moderation, +# and when the content is accepted or rejected. +# https://docs.wagtail.io/en/latest/reference/settings.html#email-notifications +WAGTAILADMIN_NOTIFICATION_FROM_EMAIL = 'admin@cdh.princeton.edu' +WAGTAILADMIN_NOTIFICATION_USE_HTML = True ################### diff --git a/cdhweb/settings.py b/cdhweb/settings.py index f16f6811b..3d6a83245 100644 --- a/cdhweb/settings.py +++ b/cdhweb/settings.py @@ -108,6 +108,22 @@ 'textarea', 'tfoot', 'th', 'thead', 'tr', 'tt', '', 'ul', 'var', 'wbr', 'iframe') +#################### +# WAGTAIL SETTINGS # +#################### + +# Human-readable name of your Wagtail site shown on login to the Wagtail admin. +# https://docs.wagtail.io/en/latest/reference/settings.html#site-name +WAGTAIL_SITE_NAME = 'CDH Website' + +# Tags are case-sensitive by default. In many cases the reverse is preferable. +# https://docs.wagtail.io/en/latest/reference/settings.html#case-insensitive-tags +TAGGIT_CASE_INSENSITIVE = True + +# Shows where a particular image, document or snippet is being used on your site. +# Generates a query which may run slowly on sites with large numbers of pages. +# https://docs.wagtail.io/en/latest/reference/settings.html#usage-for-images-documents-and-snippets +WAGTAIL_USAGE_COUNT_ENABLED = True ######################## # MAIN DJANGO SETTINGS # @@ -317,7 +333,20 @@ # "mezzanine.twitter", # "mezzanine.accounts", # "mezzanine.mobile", - "taggit", + 'wagtail.contrib.forms', + 'wagtail.contrib.redirects', + 'wagtail.contrib.search_promotions', # required to avoid https://github.com/wagtail/wagtail/issues/1824 + 'wagtail.embeds', + 'wagtail.sites', + 'wagtail.users', + 'wagtail.snippets', + 'wagtail.documents', + 'wagtail.images', + 'wagtail.search', + 'wagtail.admin', + 'wagtail.core', + 'modelcluster', + 'taggit', 'adminsortable2', "compressor", "fullurl", @@ -356,6 +385,7 @@ # "mezzanine.core.middleware.SitePermissionMiddleware", "mezzanine.pages.middleware.PageMiddleware", "mezzanine.core.middleware.FetchFromCacheMiddleware", + "wagtail.contrib.redirects.middleware.RedirectMiddleware", ) # Store these package names here as they may change in the future since @@ -423,15 +453,6 @@ sys.modules[module_name] = module exec(open(f, "rb").read()) -# if in debug mode and django-debug-toolbar is available, add to installed apps -if DEBUG: - try: - import debug_toolbar - INSTALLED_APPS.append('debug_toolbar') - except ImportError: - pass - - #################### # DYNAMIC SETTINGS # #################### diff --git a/cdhweb/urls.py b/cdhweb/urls.py index 0c32ddcb9..9fae917b7 100644 --- a/cdhweb/urls.py +++ b/cdhweb/urls.py @@ -1,13 +1,15 @@ from __future__ import unicode_literals +import debug_toolbar from django.conf import settings -from django.conf.urls import include, url from django.conf.urls.static import static -from django.conf.urls.i18n import i18n_patterns from django.contrib import admin from django.contrib.sitemaps.views import sitemap -from django.views.i18n import set_language +from django.urls import include, path, re_path from django.views.generic.base import RedirectView, TemplateView +from wagtail.admin import urls as wagtailadmin_urls +from wagtail.core import urls as wagtail_urls +from wagtail.documents import urls as wagtaildocs_urls from cdhweb.blog.sitemaps import BlogPostSitemap from cdhweb.events.sitemaps import EventSitemap @@ -18,21 +20,6 @@ admin.autodiscover() -# Add the urlpatterns for any custom Django applications here. -# You can also change the ``home`` view to add your own functionality -# to the project's homepage. - -urlpatterns = i18n_patterns( - # Change the admin prefix here to use an alternate URL for the - # admin interface, which would be marginally more secure. - url("^admin/", include(admin.site.urls)), -) - -if settings.USE_MODELTRANSLATION: - urlpatterns += [ - url('^i18n/$', set_language, name='set_language'), - ] - sitemaps = { 'blogs': BlogPostSitemap, 'events': EventSitemap, @@ -46,37 +33,54 @@ if getattr(settings, 'SHOW_TEST_WARNING', False): FAVICON = '/static/favicon-test.ico' -urlpatterns += [ - url(r'^robots\.txt$', TemplateView.as_view(template_name='robots.txt', - content_type='text/plain')), - url(r'^favicon\.ico$', RedirectView.as_view(url=FAVICON, permanent=True)), - url("^people/", include("cdhweb.people.urls", namespace='people')), - # actual blog url still TBD - url("^updates/", include("cdhweb.blog.urls", namespace='blog')), - url("^events/", include("cdhweb.events.urls", namespace='event')), - url("^projects/", include("cdhweb.projects.urls", namespace='project')), +urlpatterns = [ + # admin site + path("admin/", include(admin.site.urls)), - url("^$", resource_views.Homepage.as_view(), name="home"), + # special paths + re_path(r'^robots\.txt$', TemplateView.as_view(template_name='robots.txt', + content_type='text/plain')), + re_path(r'^favicon\.ico$', RedirectView.as_view( + url=FAVICON, permanent=True)), + re_path(r'^$', resource_views.Homepage.as_view(), name="home"), + + # debug toolbar + path("__debug__/", include(debug_toolbar.urls)), + + # main apps + path("people/", include("cdhweb.people.urls", namespace='people')), + path("updates/", include("cdhweb.blog.urls", namespace='blog')), + path("events/", include("cdhweb.events.urls", namespace='event')), + path("projects/", include("cdhweb.projects.urls", namespace='project')), # CAS login urls - url(r'^accounts/', include('pucas.cas_urls')), + path("accounts/", include('pucas.cas_urls')), # programmatic redirects from v1 site # - old staff page is now under /people/ - url(r'^about/staff/(?P[\w-]+)/$', - RedirectView.as_view(pattern_name='people:profile', permanent=True), - name='old-profile'), + re_path(r'^about/staff/(?P[\w-]+)/$', + RedirectView.as_view( + pattern_name='people:profile', permanent=True), + name='old-profile'), # - all blog urls are now under updates/ - url(r'^blog(?P.*)$', - RedirectView.as_view(url='/updates%(blog_url)s', permanent=True)), + re_path(r'^blog(?P.*)$', + RedirectView.as_view(url='/updates%(blog_url)s', permanent=True)), # override mezzanine sitemap and use locally customized sitemaps # NOTE: could use a sitemap index and grouped sitemaps here, but # may complicate testing with pa11y-ci - url(r"^sitemap\.xml$", sitemap, {'sitemaps': sitemaps}, name='sitemap'), + re_path(r"^sitemap\.xml$", sitemap, { + 'sitemaps': sitemaps}, name='sitemap'), + + # wagtail paths + # NOTE temporarily make wagtail pages available at pages/ so that they can + # coexist with mezzanine urls + path("cms/", include(wagtailadmin_urls)), + path("documents/", include(wagtaildocs_urls)), + path("pages/", include(wagtail_urls)), # let mezzanine handle everything else - url("^", include("mezzanine.urls")), + re_path(r"", include("mezzanine.urls")), ] # serve static files in development - automatically activates in DEBUG; see diff --git a/requirements/prod.txt b/requirements/prod.txt index e7b281331..ebf93468c 100644 --- a/requirements/prod.txt +++ b/requirements/prod.txt @@ -2,9 +2,11 @@ Django>=2.2,<3.0 pillow>=5.2.0 +chardet<4 # required for wagtail 2.10 git+https://github.com/stephenmcd/mezzanine.git@58aea59#egg=mezzanine # mezzanine 4.3.1 for Django 2.2 git+https://github.com/stephenmcd/filebrowser-safe.git@c7eceb0#egg=filebrowser_safe # filebrowser_safe 1.0.0-alpha.1 for Django 2.2 git+https://github.com/stephenmcd/grappelli-safe.git@7755ffd2#egg=grappelli_safe # grappelli_safe 1.0.0-alpha.1 for Django 2.2 +wagtail django-compressor django-compressor-autoprefixer psycopg2 diff --git a/templates/base.html b/templates/base.html index 354452afa..4cde91ced 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,11 +1,11 @@ -{% load static pages_tags mezzanine_tags fullurl %} +{% load static pages_tags mezzanine_tags fullurl wagtailuserbar %} {# Google Analytics recommends this implementation now #} - {% if INCLUDE_ANALYTICS %} + {% if INCLUDE_ANALYTICS and not request.is_preview %} {% endif %} - {% block page-title %}{% block page-subtitle %}{% if page %}{{ page.meta_title|add:" | "}}{% endif %}{% endblock %}The Center for Digital Humanities at Princeton{% endblock %} + {% block page-title %}{% if page %}{{ page.seo_title }}{% endif %}{% endblock %} – CDH@Princeton {% if SHOW_TEST_WARNING %} {# test variant favicon to help differentiate test/prod sites #} - + {% else %} - + {% endif %} {% include 'snippets/head_meta.html' %} From 386308dafc5f78de98c08acbd981fe5e253948c1 Mon Sep 17 00:00:00 2001 From: Nick Budak Date: Wed, 24 Mar 2021 10:54:30 -0400 Subject: [PATCH 531/570] Update all metadata, including keywords --- templates/snippets/head_meta.html | 34 +++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/templates/snippets/head_meta.html b/templates/snippets/head_meta.html index 560e37a5e..77fd0904c 100644 --- a/templates/snippets/head_meta.html +++ b/templates/snippets/head_meta.html @@ -1,20 +1,20 @@ {% load static cdh_tags %} {# html metadata #} - - - {# determine preview image: specified by page, cdh icon based on url, or default image #} - {% firstof preview_image page.get_absolute_url|url_to_icon_path default_preview_image as meta_preview_image %} - {# open graph metadata #} - - - - - - - {# twitter card #} - - - - - + + +{# determine preview image: specified by page, cdh icon based on url, or default image #} +{% firstof preview_image page.get_url|url_to_icon_path default_preview_image as meta_preview_image %} +{# open graph metadata #} + + + + + + +{# twitter card #} + + + + + From f1f8a165bc50660a6ca56896207dd7ecd87cd036 Mon Sep 17 00:00:00 2001 From: Nick Budak Date: Wed, 24 Mar 2021 14:30:22 -0400 Subject: [PATCH 532/570] Exodize tags on projects, events, and blog posts --- cdhweb/blog/exodus.py | 15 +++++++++++---- cdhweb/events/exodus.py | 13 +++++++++---- cdhweb/projects/exodus.py | 8 ++++++-- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/cdhweb/blog/exodus.py b/cdhweb/blog/exodus.py index dd46ef772..b1d3a3de8 100644 --- a/cdhweb/blog/exodus.py +++ b/cdhweb/blog/exodus.py @@ -2,10 +2,13 @@ import logging from mezzanine.core.models import CONTENT_STATUS_PUBLISHED +from taggit.models import Tag -from cdhweb.blog.models import Author, BlogLinkPage, BlogPost, OldBlogPost -from cdhweb.pages.exodus import (convert_slug, exodize_attachments, exodize_history, - get_wagtail_image, to_streamfield) +from cdhweb.blog.models import (Author, BlogLinkPage, BlogPost, BlogPostTag, + OldBlogPost) +from cdhweb.pages.exodus import (convert_slug, exodize_attachments, + exodize_history, get_wagtail_image, + to_streamfield) from cdhweb.people.models import Person @@ -58,4 +61,8 @@ def blog_exodus(): exodize_attachments(post, post_page) exodize_history(post, post_page) - # NOTE no tags to migrate + # exodize keywords as tags + for kw in post.keywords.all(): + logging.debug("exodizing blog tag %s" % kw.keyword.title) + tag = Tag.objects.get_or_create(name=kw.keyword.title)[0] + BlogPostTag.objects.create(content_object=post_page, tag=tag) diff --git a/cdhweb/events/exodus.py b/cdhweb/events/exodus.py index f63efd408..9958825bc 100644 --- a/cdhweb/events/exodus.py +++ b/cdhweb/events/exodus.py @@ -3,9 +3,11 @@ from mezzanine.core.models import CONTENT_STATUS_PUBLISHED -from cdhweb.events.models import Event, EventsLinkPage, OldEvent, Speaker -from cdhweb.pages.exodus import (convert_slug, exodize_attachments, exodize_history, - get_wagtail_image, to_streamfield) +from cdhweb.events.models import (Event, EventsLinkPage, EventTag, OldEvent, + Speaker) +from cdhweb.pages.exodus import (convert_slug, exodize_attachments, + exodize_history, get_wagtail_image, + to_streamfield) from cdhweb.people.models import Person @@ -60,4 +62,7 @@ def event_exodus(): exodize_attachments(event, event_page) exodize_history(event, event_page) - # NOTE no tags to migrate + # exodize tags + for tag in event.tags.all(): + logging.debug("exodizing event tag %s" % tag) + EventTag.objects.create(content_object=event_page, tag=tag) diff --git a/cdhweb/projects/exodus.py b/cdhweb/projects/exodus.py index d90bfde82..26810e597 100644 --- a/cdhweb/projects/exodus.py +++ b/cdhweb/projects/exodus.py @@ -6,7 +6,8 @@ from cdhweb.pages.exodus import (convert_slug, exodize_attachments, exodize_history, get_wagtail_image, to_streamfield) -from cdhweb.projects.models import OldProject, Project, ProjectsLandingPage +from cdhweb.projects.models import (OldProject, Project, ProjectsLandingPage, + ProjectTag) def project_exodus(): @@ -70,4 +71,7 @@ def project_exodus(): exodize_attachments(project, project_page) exodize_history(project, project_page) - # NOTE no tags to migrate + # exodize tags + for tag in project.tags.all(): + logging.debug("exodizing project tag %s" % tag) + ProjectTag.objects.create(content_object=project_page, tag=tag) From 9c5847093b37513f402b8ac5d727050500bb3d25 Mon Sep 17 00:00:00 2001 From: Nick Budak Date: Wed, 24 Mar 2021 17:05:05 -0400 Subject: [PATCH 533/570] Revert context obj name changes to make snippets works on homepage --- .../templates/events/event_archive.html | 4 +- .../templates/events/snippets/event_card.html | 44 +++++++++---------- .../templates/projects/project_list.html | 4 +- .../projects/snippets/project_card.html | 16 +++---- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/cdhweb/events/templates/events/event_archive.html b/cdhweb/events/templates/events/event_archive.html index 2ae7ba053..5ab770aeb 100644 --- a/cdhweb/events/templates/events/event_archive.html +++ b/cdhweb/events/templates/events/event_archive.html @@ -33,7 +33,7 @@

{{ title|default:'Upcoming' }} Events

{% endif %} -{% for page in events %} +{% for event in events %} {% include 'events/snippets/event_card.html' %} {% empty %} {# semester event archive will 404 for no events; upcoming does not #} @@ -55,7 +55,7 @@

{{ title|default:'Upcoming' }} Events

{% if past.exists %}

Past Events

- {% for page in past reversed %} {# display in chronological order #} + {% for event in past reversed %} {# display in chronological order #} {% include 'events/snippets/event_card.html' %} {% endfor %} {% endif %} diff --git a/cdhweb/events/templates/events/snippets/event_card.html b/cdhweb/events/templates/events/snippets/event_card.html index 27efad82b..2c82db1a1 100644 --- a/cdhweb/events/templates/events/snippets/event_card.html +++ b/cdhweb/events/templates/events/snippets/event_card.html @@ -1,49 +1,49 @@ {% load wagtailcore_tags wagtailimages_tags %} {# display a single event in card format #} {# FIXME: significant overlap with event_detail, esp. for schema properties #} -{% if page.thumbnail %} - {% image page.thumbnail max-310x240 as event_thumb %} +{% if event.thumbnail %} + {% image event.thumbnail max-310x240 as event_thumb %} {% endif %}
- -
{{ page.type }}
-
+
+
{{ event.type }}
+
\ No newline at end of file diff --git a/cdhweb/projects/templates/projects/project_list.html b/cdhweb/projects/templates/projects/project_list.html index 4dd3e7f91..1050051e6 100644 --- a/cdhweb/projects/templates/projects/project_list.html +++ b/cdhweb/projects/templates/projects/project_list.html @@ -29,13 +29,13 @@

{{ title }}

{% endif %} {# current projects #} -{% for page in current %} +{% for project in current %} {% include 'projects/snippets/project_card.html' with large=1 %} {% endfor %} {% if past %} {# display past if any #}

{{ past_title }}

-{% for page in past %} +{% for project in past %} {% include 'projects/snippets/project_card.html' with large=1 %} {% endfor %} {% endif %} diff --git a/cdhweb/projects/templates/projects/snippets/project_card.html b/cdhweb/projects/templates/projects/snippets/project_card.html index 8106f1a7f..f0cd51c7d 100644 --- a/cdhweb/projects/templates/projects/snippets/project_card.html +++ b/cdhweb/projects/templates/projects/snippets/project_card.html @@ -1,17 +1,17 @@ {% load wagtailcore_tags wagtailimages_tags %} {# default card display for a project #} -{% if page.thumbnail %} - {% image page.thumbnail max-310x240 as project_thumb %} +{% if project.thumbnail %} + {% image project.thumbnail max-310x240 as project_thumb %} {% endif %} From 9cdf2c3c112e0079848b000d778f9c256dd46279 Mon Sep 17 00:00:00 2001 From: Nick Budak Date: Wed, 24 Mar 2021 17:05:39 -0400 Subject: [PATCH 534/570] Fix page title calculation to use real title or view title if present --- cdhweb/pages/templates/cdhpages/home_page.html | 11 +++++------ templates/base.html | 4 +++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/cdhweb/pages/templates/cdhpages/home_page.html b/cdhweb/pages/templates/cdhpages/home_page.html index f879274f2..8e17315bf 100644 --- a/cdhweb/pages/templates/cdhpages/home_page.html +++ b/cdhweb/pages/templates/cdhpages/home_page.html @@ -1,7 +1,8 @@ {% extends 'base.html' %} {% load wagtailcore_tags %} -{% block page-title %}Home{% endblock %} +{# Override entire title so there's no extra context appended #} +{% block title %}{% firstof page.seo_title page.title %}{% endblock %} {% block content %} {# add a class to main content for home-page specific styles #}
@@ -19,15 +20,13 @@ {# display editable page content; wrapped for formatting reasons #}
- {% for block in page.body %} - {% include_block block %} - {% endfor %} + {% include_block page.body %}

Upcoming Events

-{% for page in events %} +{% for event in events %} {% include 'events/snippets/event_card.html' %} {% empty %}
@@ -39,7 +38,7 @@

Upcoming Events

Projects

-{% for page in projects %} +{% for project in projects %} {% include 'projects/snippets/project_card.html' %} {% endfor %}
diff --git a/templates/base.html b/templates/base.html index 31a5b79e8..6bf98eeec 100644 --- a/templates/base.html +++ b/templates/base.html @@ -15,7 +15,9 @@ gtag('config', 'UA-87887700-1', {'anonymize_ip': true}); {% endif %} - {% block page-title %}{% if page %}{{ page.seo_title }}{% endif %}{% endblock %} – CDH@Princeton + {% block title %} + {% block page-title %}{% firstof page.seo_title page.title page_title %}{% endblock %} – CDH@Princeton + {% endblock %} {% if SHOW_TEST_WARNING %} {# test variant favicon to help differentiate test/prod sites #} {% else %} From 163e99e4fbaba33137947b49c64675193b3f6c92 Mon Sep 17 00:00:00 2001 From: Nick Budak Date: Thu, 25 Mar 2021 10:30:19 -0400 Subject: [PATCH 535/570] Add alt to landingpage home link --- cdhweb/pages/templates/cdhpages/landing_page.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdhweb/pages/templates/cdhpages/landing_page.html b/cdhweb/pages/templates/cdhpages/landing_page.html index 8afa7fdd3..5e45c41ba 100644 --- a/cdhweb/pages/templates/cdhpages/landing_page.html +++ b/cdhweb/pages/templates/cdhpages/landing_page.html @@ -21,7 +21,7 @@
- /

{{ page.title }}

+ /

{{ page.title }}

{{ page.tagline }}

From e17e974ba8e5397cc04edd71ab1e158d1a65fb01 Mon Sep 17 00:00:00 2001 From: rlskoeser Date: Thu, 25 Mar 2021 10:24:56 -0400 Subject: [PATCH 536/570] Configure django user admin list to make it more useful for user mgmt --- cdhweb/resources/admin.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 cdhweb/resources/admin.py diff --git a/cdhweb/resources/admin.py b/cdhweb/resources/admin.py new file mode 100644 index 000000000..ec02014ed --- /dev/null +++ b/cdhweb/resources/admin.py @@ -0,0 +1,19 @@ +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin +from django.contrib.auth.models import User + + +class LocalUserAdmin(UserAdmin): + '''Customize user admin list to show last login, superuser, & groups''' + list_display = UserAdmin.list_display + \ + ('is_superuser', 'is_active', 'last_login', 'group_names') + + def group_names(self, obj): + '''custom property to display group membership''' + if obj.groups.exists(): + return ', '.join(g.name for g in obj.groups.all()) + group_names.short_description = 'groups' + + +admin.site.unregister(User) +admin.site.register(User, LocalUserAdmin) From 0c21fbeda97d5193bc24fcff536e8a453cc3ed28 Mon Sep 17 00:00:00 2001 From: Nick Budak Date: Thu, 25 Mar 2021 10:53:01 -0400 Subject: [PATCH 537/570] Don't include missing info in --- templates/snippets/head_meta.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/templates/snippets/head_meta.html b/templates/snippets/head_meta.html index 77fd0904c..f65479e8b 100644 --- a/templates/snippets/head_meta.html +++ b/templates/snippets/head_meta.html @@ -1,20 +1,20 @@ {% load static cdh_tags %} {# html metadata #} - - +{% if page.tags.exists %}{% endif %} +{% if page.search_description %}{% endif %} {# determine preview image: specified by page, cdh icon based on url, or default image #} {% firstof preview_image page.get_url|url_to_icon_path default_preview_image as meta_preview_image %} {# open graph metadata #} - + - +{% if page.search_description %}{% endif %} {# twitter card #} - - + +{% if page.search_description %}{% endif %} From 6c128a5c8859129b11d0b75ee372dd5bdfdc4b57 Mon Sep 17 00:00:00 2001 From: Nick Budak Date: Thu, 25 Mar 2021 10:53:11 -0400 Subject: [PATCH 538/570] Fix project list page default title --- cdhweb/projects/templates/projects/project_list.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdhweb/projects/templates/projects/project_list.html b/cdhweb/projects/templates/projects/project_list.html index 1050051e6..28978eee3 100644 --- a/cdhweb/projects/templates/projects/project_list.html +++ b/cdhweb/projects/templates/projects/project_list.html @@ -1,6 +1,6 @@ {% extends "base.html" %} -{% block page-title %}{{ title|default:'People' }}{% endblock %} +{% block page-title %}{{ title|default:'Projects' }}{% endblock %} {% block bodyattrs %}class="with-cards"{% endblock %} {% block main %} From 358830ffb6239f86c8844582cee755cf095ae5b8 Mon Sep 17 00:00:00 2001 From: Nick Budak Date: Thu, 25 Mar 2021 11:28:55 -0400 Subject: [PATCH 539/570] Use autoescape to fix quotes in titles/descriptions --- templates/snippets/head_meta.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/templates/snippets/head_meta.html b/templates/snippets/head_meta.html index f65479e8b..10bed4008 100644 --- a/templates/snippets/head_meta.html +++ b/templates/snippets/head_meta.html @@ -1,5 +1,6 @@ {% load static cdh_tags %} {# html metadata #} +{% autoescape on %} {% if page.tags.exists %}{% endif %} {% if page.search_description %}{% endif %} {# determine preview image: specified by page, cdh icon based on url, or default image #} @@ -17,4 +18,4 @@ {% if page.search_description %}{% endif %} - +{% endautoescape %} From 2646d358b0d64f61f422a7cf21332b1837a0affb Mon Sep 17 00:00:00 2001 From: Nick Budak Date: Thu, 25 Mar 2021 11:30:06 -0400 Subject: [PATCH 540/570] Use full post url in blogpost embedded meta --- cdhweb/blog/templates/blog/blogpost_detail.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdhweb/blog/templates/blog/blogpost_detail.html b/cdhweb/blog/templates/blog/blogpost_detail.html index ce78244a5..57f5b3492 100644 --- a/cdhweb/blog/templates/blog/blogpost_detail.html +++ b/cdhweb/blog/templates/blog/blogpost_detail.html @@ -24,7 +24,7 @@

{{ page.title }}

- + {# FIXME: do we need full url here? #} From b71dad364b8a4143cb047c9623d94f4c9968661a Mon Sep 17 00:00:00 2001 From: rlskoeser Date: Thu, 25 Mar 2021 11:59:29 -0400 Subject: [PATCH 541/570] Configure sitemap index and add sitemap for people views --- cdhweb/people/sitemaps.py | 30 +++++++++++++++++++++++------- cdhweb/urls.py | 19 +++++++++++++++++-- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/cdhweb/people/sitemaps.py b/cdhweb/people/sitemaps.py index a7c9715d5..b9c7c0f22 100644 --- a/cdhweb/people/sitemaps.py +++ b/cdhweb/people/sitemaps.py @@ -1,11 +1,27 @@ -from cdhweb.people.models import Profile -from cdhweb.resources.sitemaps import PublishedItemSitemap +from django.contrib.sitemaps import Sitemap +from django.urls import reverse +from cdhweb.people import views -class ProfileSitemap(PublishedItemSitemap): - model = Profile + +class PeopleViewsSitemap(Sitemap): + '''Sitemap for people views that are not Wagtail pages but also + not tied to models (currently archive search/browse page only).''' def items(self): - # only published profiles with is_staff actually have detail pages - # and should appear in the sitemap - return super().items().filter(is_staff=True) + # return list of tuple with url name, view object + return [ + ('staff', views.StaffListView), + ('students', views.StudentListView), + ('affiliates', views.AffiliateListView), + ('exec-committee', views.ExecListView) + ] + + def location(self, obj): + # generate url based on archives url names + return reverse('people:%s' % obj[0]) + + def lastmod(self, obj): + # both pages are modified based on changes to digitized works, + # so return the most recent modification time of any of them + return obj[1]().last_modified() diff --git a/cdhweb/urls.py b/cdhweb/urls.py index 738d25532..39ff446c1 100644 --- a/cdhweb/urls.py +++ b/cdhweb/urls.py @@ -6,10 +6,11 @@ from django.urls import include, path, re_path from django.views.generic.base import RedirectView, TemplateView from wagtail.admin import urls as wagtailadmin_urls -from wagtail.contrib.sitemaps.views import sitemap +from wagtail.contrib.sitemaps import views as sitemap_views, Sitemap from wagtail.core import urls as wagtail_urls from wagtail.documents import urls as wagtaildocs_urls +from cdhweb.people.sitemaps import PeopleViewsSitemap admin.autodiscover() @@ -18,6 +19,15 @@ if getattr(settings, 'SHOW_TEST_WARNING', False): FAVICON = '/static/favicon-test.ico' +# sitemap configuration for sections of the site +sitemaps = { + 'pages': Sitemap, # wagtail content pages + 'people': PeopleViewsSitemap, +# 'archive': ArchiveViewsSitemap, +# 'digitizedworks': DigitizedWorkSitemap, +} + + urlpatterns = [ # admin site path("admin/", include(admin.site.urls)), @@ -42,7 +52,12 @@ RedirectView.as_view(url='/updates%(blog_url)s', permanent=True)), # sitemaps - path("sitemap.xml", sitemap), + # sitemaps + path('sitemap.xml', sitemap_views.index, {'sitemaps': sitemaps}, + name='sitemap-index'), + re_path(r'^sitemap-(?P
.+)\.xml$', sitemap_views.sitemap, + {'sitemaps': sitemaps}, + name='django.contrib.sitemaps.views.sitemap'), # wagtail paths # NOTE temporarily make wagtail pages available at pages/ so that they can From 3df0e9323462233624d87a0b9b6e1389fe1db6a1 Mon Sep 17 00:00:00 2001 From: rlskoeser Date: Thu, 25 Mar 2021 16:08:17 -0400 Subject: [PATCH 542/570] Add sitemaps for project & event views --- cdhweb/events/sitemaps.py | 40 +++++++++++++++++++++++++++++++++---- cdhweb/events/views.py | 5 +++-- cdhweb/people/sitemaps.py | 2 +- cdhweb/projects/sitemaps.py | 37 +++++++++++++++++++++------------- cdhweb/urls.py | 7 +++++-- 5 files changed, 68 insertions(+), 23 deletions(-) diff --git a/cdhweb/events/sitemaps.py b/cdhweb/events/sitemaps.py index 3406debdc..700a527d9 100644 --- a/cdhweb/events/sitemaps.py +++ b/cdhweb/events/sitemaps.py @@ -1,6 +1,38 @@ -from cdhweb.events.models import Event -from cdhweb.resources.sitemaps import PublishedItemSitemap +from django.contrib.sitemaps import Sitemap +from django.test import RequestFactory +from django.urls import reverse +from cdhweb.events import views -class EventSitemap(PublishedItemSitemap): - model = Event \ No newline at end of file + +class EventViewsSitemap(Sitemap): + '''Sitemap for project views that are neither Wagtail pages nor + tied to models (currently all list views).''' + + def items(self): + # return list of tuple with url name, view object + factory = RequestFactory() + + urls = [ + (reverse('event:upcoming'), views.UpcomingEventsView()), + ] + for season, year in views.EventSemesterDates() \ + .get_semester_date_list(): + + url = reverse('event:by-semester', + kwargs={'semester': season.lower(), 'year': year}) + request = factory.get(url) + view = views.EventSemesterArchiveView() + view.setup(request) + urls.append(( + url, view + )) + return urls + + def location(self, obj): + return obj[0] + + def lastmod(self, obj): + # both pages are modified based on changes to digitized works, + # so return the most recent modification time of any of them + return obj[1].last_modified() diff --git a/cdhweb/events/views.py b/cdhweb/events/views.py index 76b9936f8..f103aed63 100644 --- a/cdhweb/events/views.py +++ b/cdhweb/events/views.py @@ -10,7 +10,7 @@ from cdhweb.pages.views import LastModifiedListMixin, LastModifiedMixin -class EventMixinView(object): +class EventMixinView: '''View mixin that sets model to Event and returns a published Event queryset.''' model = Event @@ -21,7 +21,7 @@ def get_queryset(self): return Event.objects.live() -class EventSemesterDates(object): +class EventSemesterDates: '''Mixin to return list of event semester dates based on event dates in the system.''' @@ -46,6 +46,7 @@ def get_semester_date_list(self): sem_date = (self.get_semester(date), date.year) if sem_date not in date_list: date_list.append(sem_date) + return date_list diff --git a/cdhweb/people/sitemaps.py b/cdhweb/people/sitemaps.py index b9c7c0f22..b690a0688 100644 --- a/cdhweb/people/sitemaps.py +++ b/cdhweb/people/sitemaps.py @@ -6,7 +6,7 @@ class PeopleViewsSitemap(Sitemap): '''Sitemap for people views that are not Wagtail pages but also - not tied to models (currently archive search/browse page only).''' + not tied to models (currently all people list views).''' def items(self): # return list of tuple with url name, view object diff --git a/cdhweb/projects/sitemaps.py b/cdhweb/projects/sitemaps.py index 83ab18b05..23ce306be 100644 --- a/cdhweb/projects/sitemaps.py +++ b/cdhweb/projects/sitemaps.py @@ -1,17 +1,26 @@ -from cdhweb.projects.models import Project -from cdhweb.resources.sitemaps import PublishedItemSitemap +from django.contrib.sitemaps import Sitemap +from django.urls import reverse +from cdhweb.projects import views -class ProjectSitemap(PublishedItemSitemap): - model = Project - def priority(self, item): - priority = 0.5 - # projects built by cdh should be higher priority - if item.cdh_built: - priority += 0.1 - # projects with live website should be higher priority - if item.website_url: - priority += 0.1 - # (projects built by cdh with live website will be highest priority) - return priority +class ProjectViewsSitemap(Sitemap): + '''Sitemap for project views that are neither Wagtail pages nor + tied to models (currently all project list views).''' + + def items(self): + # return list of tuple with url name, view object + return [ + ('sponsored', views.SponsoredProjectListView), + ('staff', views.StaffProjectListView), + ('working-groups', views.WorkingGroupListView), + ] + + def location(self, obj): + # generate url based on archives url names + return reverse('projects:%s' % obj[0]) + + def lastmod(self, obj): + # both pages are modified based on changes to digitized works, + # so return the most recent modification time of any of them + return obj[1]().last_modified() diff --git a/cdhweb/urls.py b/cdhweb/urls.py index 39ff446c1..28ac39c94 100644 --- a/cdhweb/urls.py +++ b/cdhweb/urls.py @@ -11,6 +11,9 @@ from wagtail.documents import urls as wagtaildocs_urls from cdhweb.people.sitemaps import PeopleViewsSitemap +from cdhweb.projects.sitemaps import ProjectViewsSitemap +from cdhweb.events.sitemaps import EventViewsSitemap + admin.autodiscover() @@ -23,8 +26,8 @@ sitemaps = { 'pages': Sitemap, # wagtail content pages 'people': PeopleViewsSitemap, -# 'archive': ArchiveViewsSitemap, -# 'digitizedworks': DigitizedWorkSitemap, + 'projects': ProjectViewsSitemap, + 'events': EventViewsSitemap, } From 18cc7faff91fb21aeac4c584b37ab8c9754ede9c Mon Sep 17 00:00:00 2001 From: rlskoeser Date: Thu, 25 Mar 2021 16:08:38 -0400 Subject: [PATCH 543/570] Correct last modified list view mixin to fix sort order, return newest --- cdhweb/pages/management/commands/exodus.py | 4 ++-- cdhweb/pages/tests/conftest.py | 4 ++++ cdhweb/pages/tests/test_views.py | 5 +++-- cdhweb/pages/views.py | 11 ++++++----- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/cdhweb/pages/management/commands/exodus.py b/cdhweb/pages/management/commands/exodus.py index 72867b09d..dadeca29d 100644 --- a/cdhweb/pages/management/commands/exodus.py +++ b/cdhweb/pages/management/commands/exodus.py @@ -193,7 +193,7 @@ def handle(self, *args, **options): # migrate people pages as link pages if people: people_pages = MezzaninePage.objects \ - .filter(slug__startswith="people/").order_by('-slug') + .filter(slug__startswith="people/") #.order_by('-slug') for page in people_pages: if page.pk not in self.migrated: create_link_page(page, people) @@ -243,7 +243,7 @@ def handle(self, *args, **options): # project list pages become link pages project_pages = MezzaninePage.objects \ - .filter(Q(slug__startswith="projects")).order_by('-slug') + .filter(Q(slug__startswith="projects")) #.order_by('-slug') for page in project_pages: if page.pk not in self.migrated: new_page = create_link_page(page, projects) diff --git a/cdhweb/pages/tests/conftest.py b/cdhweb/pages/tests/conftest.py index 8cc85d581..16e53fc76 100644 --- a/cdhweb/pages/tests/conftest.py +++ b/cdhweb/pages/tests/conftest.py @@ -92,6 +92,10 @@ def order_by(self, key): def first(self): return self.objects[0] + def reverse(self): + self.objects.reverse() + return self + class MyLastModifiedDetailView(LastModifiedMixin, DetailView): # fake view that uses LastModifiedMixin for testing diff --git a/cdhweb/pages/tests/test_views.py b/cdhweb/pages/tests/test_views.py index 816aa8fd4..aa67aa45d 100644 --- a/cdhweb/pages/tests/test_views.py +++ b/cdhweb/pages/tests/test_views.py @@ -46,7 +46,8 @@ class TestLastModifiedListMixin: def test_last_modified(self, mock_dispatch, rf, lmod_list_view, lmod_objects): """should send most recent modified date with response""" # get last modified date for most recent object - most_recent = list(sorted(lmod_objects, key=attrgetter("updated")))[0] + most_recent = list(sorted(lmod_objects, key=attrgetter("updated"), + reverse=True))[0] lmod = most_recent.updated.replace(microsecond=0) # create a fake HttpResponse and check that header is most recent date mock_dispatch.return_value = HttpResponse() @@ -68,7 +69,7 @@ def test_not_modified(self, mock_dispatch, rf, lmod_list_view, lmod_objects): assert response.status_code == 304 @patch("django.views.generic.list.ListView.dispatch") - def test_not_modified(self, mock_dispatch, rf, lmod_list_view, lmod_objects): + def test_modified(self, mock_dispatch, rf, lmod_list_view, lmod_objects): """should serve full object list with 200 if any modified since request""" # get last modified date for most recent object most_recent = list(sorted(lmod_objects, key=attrgetter("updated")))[0] diff --git a/cdhweb/pages/views.py b/cdhweb/pages/views.py index c99dce6f3..753baecc9 100644 --- a/cdhweb/pages/views.py +++ b/cdhweb/pages/views.py @@ -4,8 +4,8 @@ class LastModifiedMixin(View): """Mixin that adds last-modified timestamps to response for detail views. - - Uses Django's get_conditional_response to return a 304 if object has not + + Uses Django's get_conditional_response to return a 304 if object has not been modified since time specified in the HTTP if-modified-since header. """ @@ -36,7 +36,7 @@ def dispatch(self, request, *args, **kwargs): class LastModifiedListMixin(LastModifiedMixin): """Mixin that adds last-modified timestamps to response for list views. - + Uses Django's get_conditional_response to return a 304 if none of the objects in the list have been modified since time specified in the HTTP if-modified-since header. @@ -46,5 +46,6 @@ def last_modified(self): """Get the most recent modification date among all view objects.""" queryset = self.get_queryset() if queryset.exists(): - return getattr(queryset.order_by(self.lastmodified_attr).first(), - self.lastmodified_attr) + return getattr( + queryset.order_by(self.lastmodified_attr).reverse().first(), + self.lastmodified_attr) From cc707cdafd4b608c261d5537be717afa28f1995f Mon Sep 17 00:00:00 2001 From: rlskoeser Date: Thu, 25 Mar 2021 16:18:13 -0400 Subject: [PATCH 544/570] Correct sort order for all last modified listview tests --- cdhweb/pages/tests/test_views.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cdhweb/pages/tests/test_views.py b/cdhweb/pages/tests/test_views.py index aa67aa45d..4b2245ee4 100644 --- a/cdhweb/pages/tests/test_views.py +++ b/cdhweb/pages/tests/test_views.py @@ -59,7 +59,8 @@ def test_last_modified(self, mock_dispatch, rf, lmod_list_view, lmod_objects): def test_not_modified(self, mock_dispatch, rf, lmod_list_view, lmod_objects): """should serve 304 if no objects have been modified since request""" # get last modified date for most recent object - most_recent = list(sorted(lmod_objects, key=attrgetter("updated")))[0] + most_recent = list(sorted(lmod_objects, key=attrgetter("updated"), + reverse=True))[0] lmod = most_recent.updated + timedelta(seconds=1) request = rf.get("", HTTP_IF_MODIFIED_SINCE=lmod.strftime( "%a, %d %b %Y %H:%M:%S GMT")) @@ -72,7 +73,8 @@ def test_not_modified(self, mock_dispatch, rf, lmod_list_view, lmod_objects): def test_modified(self, mock_dispatch, rf, lmod_list_view, lmod_objects): """should serve full object list with 200 if any modified since request""" # get last modified date for most recent object - most_recent = list(sorted(lmod_objects, key=attrgetter("updated")))[0] + most_recent = list(sorted(lmod_objects, key=attrgetter("updated"), + reverse=True))[0] lmod = most_recent.updated - timedelta(days=1) # request with prior date; should report modified since then request = rf.get("", HTTP_IF_MODIFIED_SINCE=lmod.strftime( From 33605f9f19de6e38e18a2ce17500105dd43dd64a Mon Sep 17 00:00:00 2001 From: rlskoeser Date: Thu, 25 Mar 2021 16:30:24 -0400 Subject: [PATCH 545/570] Preserve nav order when migrating people and project list pages --- cdhweb/pages/management/commands/exodus.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cdhweb/pages/management/commands/exodus.py b/cdhweb/pages/management/commands/exodus.py index dadeca29d..eeebcbb96 100644 --- a/cdhweb/pages/management/commands/exodus.py +++ b/cdhweb/pages/management/commands/exodus.py @@ -193,7 +193,7 @@ def handle(self, *args, **options): # migrate people pages as link pages if people: people_pages = MezzaninePage.objects \ - .filter(slug__startswith="people/") #.order_by('-slug') + .filter(slug__startswith="people/").order_by('_order') for page in people_pages: if page.pk not in self.migrated: create_link_page(page, people) @@ -243,7 +243,7 @@ def handle(self, *args, **options): # project list pages become link pages project_pages = MezzaninePage.objects \ - .filter(Q(slug__startswith="projects")) #.order_by('-slug') + .filter(Q(slug__startswith="projects")).order_by('_order') for page in project_pages: if page.pk not in self.migrated: new_page = create_link_page(page, projects) From 0c796df7e3cf728fc5f997d3552260065929f37c Mon Sep 17 00:00:00 2001 From: rlskoeser Date: Thu, 25 Mar 2021 16:30:38 -0400 Subject: [PATCH 546/570] Cleanup inaccurate comments --- cdhweb/urls.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cdhweb/urls.py b/cdhweb/urls.py index 28ac39c94..5ab745c41 100644 --- a/cdhweb/urls.py +++ b/cdhweb/urls.py @@ -54,7 +54,6 @@ re_path(r'^blog(?P.*)$', RedirectView.as_view(url='/updates%(blog_url)s', permanent=True)), - # sitemaps # sitemaps path('sitemap.xml', sitemap_views.index, {'sitemaps': sitemaps}, name='sitemap-index'), @@ -63,13 +62,13 @@ name='django.contrib.sitemaps.views.sitemap'), # wagtail paths - # NOTE temporarily make wagtail pages available at pages/ so that they can # coexist with mezzanine urls path("cms/", include(wagtailadmin_urls)), path("documents/", include(wagtaildocs_urls)), # enable if needed to test mezzanine pages # path("mezz", include("mezzanine.urls")), + # let wagtail handle everything else path("", include(wagtail_urls)), ] From a4394b8e47d365fd4ea829a71c2216b46dd70b2e Mon Sep 17 00:00:00 2001 From: rlskoeser Date: Thu, 25 Mar 2021 17:19:57 -0400 Subject: [PATCH 547/570] Remove unneeded Q filter --- cdhweb/pages/management/commands/exodus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdhweb/pages/management/commands/exodus.py b/cdhweb/pages/management/commands/exodus.py index eeebcbb96..83b2ea8d4 100644 --- a/cdhweb/pages/management/commands/exodus.py +++ b/cdhweb/pages/management/commands/exodus.py @@ -243,7 +243,7 @@ def handle(self, *args, **options): # project list pages become link pages project_pages = MezzaninePage.objects \ - .filter(Q(slug__startswith="projects")).order_by('_order') + .filter(slug__startswith="projects").order_by('_order') for page in project_pages: if page.pk not in self.migrated: new_page = create_link_page(page, projects) From febd671985e06e825df669963bf593f9358924e2 Mon Sep 17 00:00:00 2001 From: rlskoeser Date: Thu, 25 Mar 2021 17:20:21 -0400 Subject: [PATCH 548/570] Clean up copypasta'd sitemap comments --- cdhweb/events/sitemaps.py | 12 +++++++----- cdhweb/people/sitemaps.py | 5 ++--- cdhweb/projects/sitemaps.py | 5 ++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cdhweb/events/sitemaps.py b/cdhweb/events/sitemaps.py index 700a527d9..430b36957 100644 --- a/cdhweb/events/sitemaps.py +++ b/cdhweb/events/sitemaps.py @@ -7,18 +7,20 @@ class EventViewsSitemap(Sitemap): '''Sitemap for project views that are neither Wagtail pages nor - tied to models (currently all list views).''' + tied to models (currently event upcoming and semester list views).''' def items(self): - # return list of tuple with url name, view object + # return list of tuple with url, initialized view object factory = RequestFactory() urls = [ (reverse('event:upcoming'), views.UpcomingEventsView()), ] + # get list of actual semesters with events for season, year in views.EventSemesterDates() \ .get_semester_date_list(): - + # generate url for this date, + # and initialize a view for that url so we can get last modified url = reverse('event:by-semester', kwargs={'semester': season.lower(), 'year': year}) request = factory.get(url) @@ -30,9 +32,9 @@ def items(self): return urls def location(self, obj): + # return the url as generated in items method return obj[0] def lastmod(self, obj): - # both pages are modified based on changes to digitized works, - # so return the most recent modification time of any of them + # return last modified as calculated by the view return obj[1].last_modified() diff --git a/cdhweb/people/sitemaps.py b/cdhweb/people/sitemaps.py index b690a0688..ee0c58036 100644 --- a/cdhweb/people/sitemaps.py +++ b/cdhweb/people/sitemaps.py @@ -18,10 +18,9 @@ def items(self): ] def location(self, obj): - # generate url based on archives url names + # generate url based on url name within people url namespace return reverse('people:%s' % obj[0]) def lastmod(self, obj): - # both pages are modified based on changes to digitized works, - # so return the most recent modification time of any of them + # return last modified as calculated by the view return obj[1]().last_modified() diff --git a/cdhweb/projects/sitemaps.py b/cdhweb/projects/sitemaps.py index 23ce306be..782b32977 100644 --- a/cdhweb/projects/sitemaps.py +++ b/cdhweb/projects/sitemaps.py @@ -17,10 +17,9 @@ def items(self): ] def location(self, obj): - # generate url based on archives url names + # generate url based on url name within projects url namespace return reverse('projects:%s' % obj[0]) def lastmod(self, obj): - # both pages are modified based on changes to digitized works, - # so return the most recent modification time of any of them + # return last modified as calculated by the view return obj[1]().last_modified() From 17f33d1c46b7d0135eca7add050682da15583d40 Mon Sep 17 00:00:00 2001 From: rlskoeser Date: Thu, 25 Mar 2021 17:20:43 -0400 Subject: [PATCH 549/570] Add tests for people, projects, and event sitemaps --- cdhweb/events/tests/test_sitemaps.py | 42 ++++++++++++++++++++++++++ cdhweb/people/tests/test_sitemaps.py | 36 ++++++++++++++++++++++ cdhweb/projects/tests/test_sitemaps.py | 37 +++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 cdhweb/events/tests/test_sitemaps.py create mode 100644 cdhweb/people/tests/test_sitemaps.py create mode 100644 cdhweb/projects/tests/test_sitemaps.py diff --git a/cdhweb/events/tests/test_sitemaps.py b/cdhweb/events/tests/test_sitemaps.py new file mode 100644 index 000000000..06cc6a568 --- /dev/null +++ b/cdhweb/events/tests/test_sitemaps.py @@ -0,0 +1,42 @@ +from django.urls import reverse +import pytest + +from cdhweb.events import views +from cdhweb.events.sitemaps import EventViewsSitemap + + +class TestEventViewsSitemap: + + @pytest.mark.django_db + def test_items(self, deadline): + semester_dates = views.EventSemesterDates().get_semester_date_list() + + items = EventViewsSitemap().items() + # expect one for each semester date plus upcoming + assert len(items) == len(semester_dates) + 1 + + urls = [i[0] for i in items] + url_views = [i[1] for i in items] + + assert reverse('events:upcoming') in urls + # views should be instantiated, since semester archive needs args + assert isinstance(url_views[0], views.UpcomingEventsView) + assert isinstance(url_views[1], views.EventSemesterArchiveView) + + def test_location(self): + loc = reverse('events:upcoming') + # location is returned as is + assert EventViewsSitemap().location((loc,)) == loc + + @pytest.mark.django_db + def test_lastmod(self, deadline): + # fixture to ensure we have at least one upcoming event + assert EventViewsSitemap().lastmod(('upcoming', + views.UpcomingEventsView())) ==\ + views.UpcomingEventsView().last_modified() + + @pytest.mark.django_db + def test_get(self, client): + # test that it actually renders, to catch any other problems + resp = client.get('/sitemap-events.xml') + assert resp.status_code == 200 diff --git a/cdhweb/people/tests/test_sitemaps.py b/cdhweb/people/tests/test_sitemaps.py new file mode 100644 index 000000000..5e7552171 --- /dev/null +++ b/cdhweb/people/tests/test_sitemaps.py @@ -0,0 +1,36 @@ +from django.urls import reverse +import pytest + +from cdhweb.people import views +from cdhweb.people.sitemaps import PeopleViewsSitemap + + +class TestPeopleViewsSitemap: + + def test_items(self): + items = PeopleViewsSitemap().items() + url_names = [i[0] for i in items] + url_views = [i[1] for i in items] + + for url_name in ['staff', 'students', 'affiliates', 'exec-committee']: + assert url_name in url_names + + for view in [views.StaffListView, views.StudentListView, + views.AffiliateListView, views.ExecListView]: + assert view in url_views + + def test_location(self): + assert PeopleViewsSitemap().location(('staff',)) \ + == reverse('people:staff') + + @pytest.mark.django_db + def test_lastmod(self, staffer): + # fixture to ensure we have at least one record with a date + assert PeopleViewsSitemap().lastmod(('staff', views.StaffListView)) ==\ + views.StaffListView().last_modified() + + @pytest.mark.django_db + def test_get(self, client): + # test that it actually renders, to catch any other problems + resp = client.get('/sitemap-people.xml') + assert resp.status_code == 200 diff --git a/cdhweb/projects/tests/test_sitemaps.py b/cdhweb/projects/tests/test_sitemaps.py new file mode 100644 index 000000000..a1172afb3 --- /dev/null +++ b/cdhweb/projects/tests/test_sitemaps.py @@ -0,0 +1,37 @@ +from django.urls import reverse +import pytest + +from cdhweb.projects import views +from cdhweb.projects.sitemaps import ProjectViewsSitemap + + +class TestProjectViewsSitemap: + + def test_items(self): + items = ProjectViewsSitemap().items() + url_names = [i[0] for i in items] + url_views = [i[1] for i in items] + + for url_name in ['sponsored', 'staff', 'working-groups']: + assert url_name in url_names + + for view in [views.SponsoredProjectListView, + views.StaffProjectListView, views.WorkingGroupListView]: + assert view in url_views + + def test_location(self): + assert ProjectViewsSitemap().location(('staff',)) \ + == reverse('projects:staff') + + @pytest.mark.django_db + def test_lastmod(self, derrida): + # fixture to ensure we have at least one record with a date + assert ProjectViewsSitemap().lastmod(('staff', + views.StaffProjectListView)) == \ + views.StaffProjectListView().last_modified() + + @pytest.mark.django_db + def test_get(self, client): + # test that it actually renders, to catch any other problems + resp = client.get('/sitemap-projects.xml') + assert resp.status_code == 200 From 6c2d38aad0d4141273dd1e7318bc968d52e0b187 Mon Sep 17 00:00:00 2001 From: rlskoeser Date: Thu, 25 Mar 2021 18:01:42 -0400 Subject: [PATCH 550/570] Add and test sitemap for blog list views --- cdhweb/blog/sitemaps.py | 54 ++++++++++++++++++++++++++++++ cdhweb/blog/tests/test_sitemaps.py | 48 ++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 cdhweb/blog/sitemaps.py create mode 100644 cdhweb/blog/tests/test_sitemaps.py diff --git a/cdhweb/blog/sitemaps.py b/cdhweb/blog/sitemaps.py new file mode 100644 index 000000000..983d20ee8 --- /dev/null +++ b/cdhweb/blog/sitemaps.py @@ -0,0 +1,54 @@ +from django.contrib.sitemaps import Sitemap +from django.urls import reverse + +from cdhweb.blog.models import BlogPost + + +class BlogListSitemap(Sitemap): + '''Sitemap for block views that are neither Wagtail pages nor + tied to models (currently event recent and archive list views).''' + + def items(self): + # return list of tuples for identifying blog list views + # - could be url name, year, or year + month + # factory = RequestFactory() + + items = [ + ('list',) + ] + + live_posts = BlogPost.objects.live() + for date in live_posts.dates('first_published_at', 'year', + order='DESC'): + items.append((date.year,)) + + for date in live_posts.dates('first_published_at', 'month', + order='DESC'): + items.append((date.year, date.month)) + return items + + def location(self, obj): + # determine url to generate based on length/content + # two args — year/month archive + if len(obj) == 2: + return reverse('blog:by-month', kwargs={'year': obj[0], + 'month': '%02d' % obj[1]}) + # single arg, numeric — year archive + elif str(obj[0]).isdigit(): + return reverse('blog:by-year', args=obj) + # non-numeric — named url + else: + return reverse('blog:%s' % obj[0]) + + return obj[0] + + def lastmod(self, obj): + posts = BlogPost.objects.live().order_by('-first_published_at') + # if first element is numeric, filter by year + if str(obj[0]).isdigit(): + posts = posts.filter(first_published_at__year=obj[0]) + # if two args, also filter by month + if len(obj) == 2: + posts = posts.filter(first_published_at__month=obj[1]) + + return posts.first().first_published_at diff --git a/cdhweb/blog/tests/test_sitemaps.py b/cdhweb/blog/tests/test_sitemaps.py new file mode 100644 index 000000000..b38141b85 --- /dev/null +++ b/cdhweb/blog/tests/test_sitemaps.py @@ -0,0 +1,48 @@ +from django.urls import reverse +import pytest + +from cdhweb.blog.sitemaps import BlogListSitemap + + +class TestBlogListSitemap: + + @pytest.mark.django_db + def test_items(self, announcement): + items = BlogListSitemap().items() + # expect three: list, year, year+month + assert len(items) == 3 + + assert ('list',) in items + assert (announcement.first_published_at.year, ) in items + assert (announcement.first_published_at.year, + announcement.first_published_at.month) in items + + def test_location(self): + # named url + assert BlogListSitemap().location(('list',)) == reverse('blog:list') + # year only + assert BlogListSitemap().location((2020,)) == \ + reverse('blog:by-year', args=[2020]) + # year + month; requires two-digit month + assert BlogListSitemap().location((2019, 3)) == \ + reverse('blog:by-month', args=[2019, '03']) + + @pytest.mark.django_db + def test_lastmod(self, announcement, article): + # announcement fixture published yesterday, most recent for list + blogsitemap = BlogListSitemap() + assert blogsitemap.lastmod(('list', )) \ + == announcement.first_published_at + + assert blogsitemap.lastmod((article.first_published_at.year, )) \ + == article.first_published_at + + assert blogsitemap.lastmod((article.first_published_at.year, + article.first_published_at.month)) \ + == article.first_published_at + + @pytest.mark.django_db + def test_get(self, client, announcement): + # test that it actually renders, to catch any other problems + resp = client.get('/sitemap-blog.xml') + assert resp.status_code == 200 From 7d2b2eae2c256db6f07224488623fe08d5e22f7c Mon Sep 17 00:00:00 2001 From: rlskoeser Date: Thu, 25 Mar 2021 18:02:02 -0400 Subject: [PATCH 551/570] Rename list view sitemaps to be more informative --- cdhweb/events/sitemaps.py | 4 ++-- cdhweb/events/tests/test_sitemaps.py | 12 ++++++------ cdhweb/people/sitemaps.py | 2 +- cdhweb/people/tests/test_sitemaps.py | 10 +++++----- cdhweb/projects/sitemaps.py | 2 +- cdhweb/projects/tests/test_sitemaps.py | 12 ++++++------ cdhweb/urls.py | 14 ++++++++------ 7 files changed, 29 insertions(+), 27 deletions(-) diff --git a/cdhweb/events/sitemaps.py b/cdhweb/events/sitemaps.py index 430b36957..a1b5fb419 100644 --- a/cdhweb/events/sitemaps.py +++ b/cdhweb/events/sitemaps.py @@ -5,8 +5,8 @@ from cdhweb.events import views -class EventViewsSitemap(Sitemap): - '''Sitemap for project views that are neither Wagtail pages nor +class EventListSitemap(Sitemap): + '''Sitemap for event views that are neither Wagtail pages nor tied to models (currently event upcoming and semester list views).''' def items(self): diff --git a/cdhweb/events/tests/test_sitemaps.py b/cdhweb/events/tests/test_sitemaps.py index 06cc6a568..7da8496ea 100644 --- a/cdhweb/events/tests/test_sitemaps.py +++ b/cdhweb/events/tests/test_sitemaps.py @@ -2,16 +2,16 @@ import pytest from cdhweb.events import views -from cdhweb.events.sitemaps import EventViewsSitemap +from cdhweb.events.sitemaps import EventListSitemap -class TestEventViewsSitemap: +class TestEventListSitemap: @pytest.mark.django_db def test_items(self, deadline): semester_dates = views.EventSemesterDates().get_semester_date_list() - items = EventViewsSitemap().items() + items = EventListSitemap().items() # expect one for each semester date plus upcoming assert len(items) == len(semester_dates) + 1 @@ -26,13 +26,13 @@ def test_items(self, deadline): def test_location(self): loc = reverse('events:upcoming') # location is returned as is - assert EventViewsSitemap().location((loc,)) == loc + assert EventListSitemap().location((loc,)) == loc @pytest.mark.django_db def test_lastmod(self, deadline): # fixture to ensure we have at least one upcoming event - assert EventViewsSitemap().lastmod(('upcoming', - views.UpcomingEventsView())) ==\ + assert EventListSitemap().lastmod(('upcoming', + views.UpcomingEventsView())) ==\ views.UpcomingEventsView().last_modified() @pytest.mark.django_db diff --git a/cdhweb/people/sitemaps.py b/cdhweb/people/sitemaps.py index ee0c58036..b9da0e8cc 100644 --- a/cdhweb/people/sitemaps.py +++ b/cdhweb/people/sitemaps.py @@ -4,7 +4,7 @@ from cdhweb.people import views -class PeopleViewsSitemap(Sitemap): +class PeopleListSitemap(Sitemap): '''Sitemap for people views that are not Wagtail pages but also not tied to models (currently all people list views).''' diff --git a/cdhweb/people/tests/test_sitemaps.py b/cdhweb/people/tests/test_sitemaps.py index 5e7552171..430d47928 100644 --- a/cdhweb/people/tests/test_sitemaps.py +++ b/cdhweb/people/tests/test_sitemaps.py @@ -2,13 +2,13 @@ import pytest from cdhweb.people import views -from cdhweb.people.sitemaps import PeopleViewsSitemap +from cdhweb.people.sitemaps import PeopleListSitemap -class TestPeopleViewsSitemap: +class TestPeopleListSitemap: def test_items(self): - items = PeopleViewsSitemap().items() + items = PeopleListSitemap().items() url_names = [i[0] for i in items] url_views = [i[1] for i in items] @@ -20,13 +20,13 @@ def test_items(self): assert view in url_views def test_location(self): - assert PeopleViewsSitemap().location(('staff',)) \ + assert PeopleListSitemap().location(('staff',)) \ == reverse('people:staff') @pytest.mark.django_db def test_lastmod(self, staffer): # fixture to ensure we have at least one record with a date - assert PeopleViewsSitemap().lastmod(('staff', views.StaffListView)) ==\ + assert PeopleListSitemap().lastmod(('staff', views.StaffListView)) ==\ views.StaffListView().last_modified() @pytest.mark.django_db diff --git a/cdhweb/projects/sitemaps.py b/cdhweb/projects/sitemaps.py index 782b32977..9d5beae7c 100644 --- a/cdhweb/projects/sitemaps.py +++ b/cdhweb/projects/sitemaps.py @@ -4,7 +4,7 @@ from cdhweb.projects import views -class ProjectViewsSitemap(Sitemap): +class ProjectListSitemap(Sitemap): '''Sitemap for project views that are neither Wagtail pages nor tied to models (currently all project list views).''' diff --git a/cdhweb/projects/tests/test_sitemaps.py b/cdhweb/projects/tests/test_sitemaps.py index a1172afb3..a3c2f1838 100644 --- a/cdhweb/projects/tests/test_sitemaps.py +++ b/cdhweb/projects/tests/test_sitemaps.py @@ -2,13 +2,13 @@ import pytest from cdhweb.projects import views -from cdhweb.projects.sitemaps import ProjectViewsSitemap +from cdhweb.projects.sitemaps import ProjectListSitemap -class TestProjectViewsSitemap: +class TestProjectListSitemap: def test_items(self): - items = ProjectViewsSitemap().items() + items = ProjectListSitemap().items() url_names = [i[0] for i in items] url_views = [i[1] for i in items] @@ -20,14 +20,14 @@ def test_items(self): assert view in url_views def test_location(self): - assert ProjectViewsSitemap().location(('staff',)) \ + assert ProjectListSitemap().location(('staff',)) \ == reverse('projects:staff') @pytest.mark.django_db def test_lastmod(self, derrida): # fixture to ensure we have at least one record with a date - assert ProjectViewsSitemap().lastmod(('staff', - views.StaffProjectListView)) == \ + assert ProjectListSitemap().lastmod(('staff', + views.StaffProjectListView)) == \ views.StaffProjectListView().last_modified() @pytest.mark.django_db diff --git a/cdhweb/urls.py b/cdhweb/urls.py index 5ab745c41..62bd4cdc4 100644 --- a/cdhweb/urls.py +++ b/cdhweb/urls.py @@ -10,9 +10,10 @@ from wagtail.core import urls as wagtail_urls from wagtail.documents import urls as wagtaildocs_urls -from cdhweb.people.sitemaps import PeopleViewsSitemap -from cdhweb.projects.sitemaps import ProjectViewsSitemap -from cdhweb.events.sitemaps import EventViewsSitemap +from cdhweb.blog.sitemaps import BlogListSitemap +from cdhweb.people.sitemaps import PeopleListSitemap +from cdhweb.projects.sitemaps import ProjectListSitemap +from cdhweb.events.sitemaps import EventListSitemap admin.autodiscover() @@ -25,9 +26,10 @@ # sitemap configuration for sections of the site sitemaps = { 'pages': Sitemap, # wagtail content pages - 'people': PeopleViewsSitemap, - 'projects': ProjectViewsSitemap, - 'events': EventViewsSitemap, + 'people': PeopleListSitemap, + 'projects': ProjectListSitemap, + 'events': EventListSitemap, + 'blog': BlogListSitemap, } From 77f362b254bca43c0531a475bedec71802d4261b Mon Sep 17 00:00:00 2001 From: rlskoeser Date: Thu, 25 Mar 2021 18:06:52 -0400 Subject: [PATCH 552/570] Remove old mezzanine sitemap code --- cdhweb/resources/sitemaps.py | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 cdhweb/resources/sitemaps.py diff --git a/cdhweb/resources/sitemaps.py b/cdhweb/resources/sitemaps.py deleted file mode 100644 index 530fe8561..000000000 --- a/cdhweb/resources/sitemaps.py +++ /dev/null @@ -1,27 +0,0 @@ -from django.contrib.sitemaps import Sitemap -from django.core.exceptions import ObjectDoesNotExist - -from mezzanine.pages.models import Page - - -class PublishedItemSitemap(Sitemap): - '''Generic sitemap with common logic for displayable models''' - - #: django model to use for items - model = None - - def items(self): - return self.model.objects.published() - - # location uses get_absolute_url by default - - def lastmod(self, item): - return item.updated or item.published - - -class PageSitemap(PublishedItemSitemap): - '''Sitemap for pages; includes rich text pages and landing pages''' - model = Page - - def items(self): - return super().items().filter(in_sitemap=True) From 2a4cc4c1f2285644f71423515386e8af9459bd4c Mon Sep 17 00:00:00 2001 From: rlskoeser Date: Thu, 25 Mar 2021 18:07:14 -0400 Subject: [PATCH 553/570] Remove redundant/outdated child pages test --- cdhweb/resources/tests/test_views.py | 36 ---------------------------- 1 file changed, 36 deletions(-) diff --git a/cdhweb/resources/tests/test_views.py b/cdhweb/resources/tests/test_views.py index ae382e4e9..49380caa6 100644 --- a/cdhweb/resources/tests/test_views.py +++ b/cdhweb/resources/tests/test_views.py @@ -1,44 +1,8 @@ -import string -from datetime import timedelta -from unittest import skip - from django.contrib.sites.models import Site -from django.test import TestCase -from django.urls import reverse -from django.utils import timezone -from mezzanine.pages.models import Page -from mezzanine.core.models import CONTENT_STATUS_DRAFT import pytest -from cdhweb.blog.models import BlogPost -from cdhweb.events.models import Event, EventType -from cdhweb.projects.models import Project, GrantType, Grant -from cdhweb.resources.models import LandingPage -from cdhweb.resources.sitemaps import PageSitemap from cdhweb.resources.utils import absolutize_url -@skip("fixme - move to pages") -class TestViews(TestCase): - fixtures = ['test_pages.json'] - - def test_child_pages_attachment(self): - about = Page.objects.get(title='About') - annual_report = Page.objects.get(title='Annual Report') - response = self.client.get(about.get_absolute_url()) - # page-children attachment section should be present - self.assertContains( - response, '
') - # child page title and url should be present - self.assertContains(response, annual_report.title) - self.assertContains(response, annual_report.get_absolute_url()) - - # delete child page to check behavior without - annual_report.delete() - response = self.client.get(about.get_absolute_url()) - # should not error, should not contain page-children attachment section - self.assertNotContains( - response, '
') - @pytest.mark.django_db def test_absolutize_url(): From 24b6e8cc1a6303756283ce2d58cd8359dd9015ed Mon Sep 17 00:00:00 2001 From: Nick Budak Date: Mon, 29 Mar 2021 14:08:27 -0400 Subject: [PATCH 554/570] Correct admin search field naming for Events --- cdhweb/events/wagtail_hooks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdhweb/events/wagtail_hooks.py b/cdhweb/events/wagtail_hooks.py index dfb4828c0..8d40f093a 100644 --- a/cdhweb/events/wagtail_hooks.py +++ b/cdhweb/events/wagtail_hooks.py @@ -15,7 +15,7 @@ class EventAdmin(ThumbnailMixin, ModelAdmin): "speaker_list", "attendance", "join_url", "content", "tags", "updated") export_filename = "cdhweb-events" search_fields = ("title", "speakers__person__first_name", - "speakers__person__last_name", "content", "type", + "speakers__person__last_name", "body", "type", "sponsor", "location") exclude_from_explorer = True thumb_image_field_name = "thumbnail" From 3856bc0991292b5c04e77436047627b442446401 Mon Sep 17 00:00:00 2001 From: Nick Budak Date: Mon, 29 Mar 2021 14:25:06 -0400 Subject: [PATCH 555/570] Remove broken attachment exodus check --- cdhweb/pages/management/commands/exodus.py | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/cdhweb/pages/management/commands/exodus.py b/cdhweb/pages/management/commands/exodus.py index 83b2ea8d4..519ce7c46 100644 --- a/cdhweb/pages/management/commands/exodus.py +++ b/cdhweb/pages/management/commands/exodus.py @@ -216,7 +216,8 @@ def handle(self, *args, **options): Redirect.add_redirect( '/projects/about/', redirect_to=projects, is_permanent=True) except MezzaninePage.DoesNotExist: - logging.warning("no projects landing page found; skipping projects") + logging.warning( + "no projects landing page found; skipping projects") pass if projects: @@ -294,19 +295,6 @@ def handle(self, *args, **options): for page in unmigrated: print('\t%s — slug/url %s)' % (page, page.slug)) - # report on unmigrated attachments - attachment_pages = set(chain.from_iterable( - [a.pages.all() for a in Attachment.objects.all()])) - new_attachment_pages = list(filter(lambda p: hasattr(p, "attachments"), - Page.objects.all())) - n_old_pages = len(attachment_pages) - n_new_pages = len(new_attachment_pages) - if n_old_pages > n_new_pages: - missing_pages = set([p.title for p in attachment_pages]) - \ - set([p.title for p in new_attachment_pages]) - logging.warning("%d pages with umigrated attachments: %s" % ( - n_old_pages - n_new_pages, ", ".join(missing_pages))) - # delete mezzanine pages here? (but keep for testing migration) def get_collection(self, name): From 57b33f834ac891652566299f1c03536149dfdc80 Mon Sep 17 00:00:00 2001 From: rlskoeser Date: Mon, 29 Mar 2021 16:17:50 -0400 Subject: [PATCH 556/570] Set primary nav links active if current url starts with nav url --- cdhweb/resources/templatetags/cdh_tags.py | 8 ++++++++ cdhweb/resources/tests/test_tags.py | 6 ++++++ templates/snippets/navigation_card.html | 3 ++- templates/snippets/primary_navigation.html | 4 ++-- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/cdhweb/resources/templatetags/cdh_tags.py b/cdhweb/resources/templatetags/cdh_tags.py index 4de9cd754..5aad4ad5c 100644 --- a/cdhweb/resources/templatetags/cdh_tags.py +++ b/cdhweb/resources/templatetags/cdh_tags.py @@ -36,6 +36,7 @@ def url_to_icon(value): return icon return '' + @register.filter def url_to_icon_path(value): '''Return absolute path to CDH icon name based on URL.''' @@ -43,3 +44,10 @@ def url_to_icon_path(value): if img: return absolutize_url('{}img/cdh-icons/png@2X/{}@2x.png'.format(settings.STATIC_URL, img)) return '' + + +@register.filter('startswith') +def startswith(text, starts): + if isinstance(text, str): + return text.startswith(starts) + return False diff --git a/cdhweb/resources/tests/test_tags.py b/cdhweb/resources/tests/test_tags.py index 25f33d8df..5d2442817 100644 --- a/cdhweb/resources/tests/test_tags.py +++ b/cdhweb/resources/tests/test_tags.py @@ -21,3 +21,9 @@ def test_url_to_icon_path(): domain = Site.objects.get_current().domain assert cdh_tags.url_to_icon_path('/people/staff/') == \ 'https://{}/static/img/cdh-icons/png@2X/ppl@2x.png'.format(domain) + + +def test_startswith(): + assert cdh_tags.startswith('yes', 'y') + assert not cdh_tags.startswith('no', 'y') + assert not cdh_tags.startswith(3, 'y') diff --git a/templates/snippets/navigation_card.html b/templates/snippets/navigation_card.html index f1c393702..3d94d0f7e 100644 --- a/templates/snippets/navigation_card.html +++ b/templates/snippets/navigation_card.html @@ -1,4 +1,5 @@ {# secondary and tertiary naviation for the top-level of the site #} +{% load cdh_tags %} {% if navpages %}