From 51ca20335ac9d9680321ac6d1c38537585da6321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Mon, 25 Mar 2019 00:09:35 +0100 Subject: [PATCH 01/15] Sketch :cucumber: for #240 --- cypress/integration/common/steps.js | 4 ++ .../identifier/PersistentLinks.feature | 41 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 cypress/integration/identifier/PersistentLinks.feature diff --git a/cypress/integration/common/steps.js b/cypress/integration/common/steps.js index 1a9891a7a..d05f80f13 100644 --- a/cypress/integration/common/steps.js +++ b/cypress/integration/common/steps.js @@ -86,6 +86,10 @@ Given('my user account has the role {string}', role => { When('I log out', cy.logout) +When('I visit {string}', page => { + cy.openPage(page) +}) + When('I visit the {string} page', page => { cy.openPage(page) }) diff --git a/cypress/integration/identifier/PersistentLinks.feature b/cypress/integration/identifier/PersistentLinks.feature new file mode 100644 index 000000000..b4a55cee3 --- /dev/null +++ b/cypress/integration/identifier/PersistentLinks.feature @@ -0,0 +1,41 @@ +Feature: Persistent Links + As a user + I want to click on a link with an 'href' having an unmodifiable id of a user + In order to have persistent links even if the user changes a his/her slug + + | | Modifiable | Referenceable | Unique | Purpose | + | -- | -- | -- | -- | -- | + | ID | no | yes | yes | Identity, Traceability, Links | + | Slug | yes | yes | yes | @-Mentions, SEO-friendly URL | + | Name | yes | no | no | Search, self-description | + + + Background: + Given we have the following user accounts: + | id | name | slug | + | MHNqce98y1 | Stepen Hawking | thehawk | + And we have the following posts in our database: + | id | title | slug | + | bWBjpkTKZp | 101 Essays that will change the way you think | 101-essays | + And I have a user account + And I am logged in + + Scenario Outline: Link with slug only is valid and gets auto-completed + When I visit "" + Then I get redirected to "" + Examples: + | url | redirectUrl | + | /profile/thehawk | /profile/MHNqce98y1/thehawk | + | /post/101-essays | /post/bWBjpkTKZp/101-essays | + + Scenario: Link with id only will always point to the same user + When I visit "/profile/MHNqce98y1" + Then I get redirected to "/profile/MHNqce98y1/thehawk" + + Scenario Outline: ID takes precedence over slug + When I visit "" + Then I get redirected to "" + Examples: + | url | redirectUrl | + | /profile/MHNqce98y1/stephen-hawking | /profile/MHNqce98y1/thehawk | + | /post/bWBjpkTKZp/the-way-you-think | /post/bWBjpkTKZp/101-essays | From 327bd037a019a535703004f31283793d8e6cd9a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Mon, 25 Mar 2019 14:49:54 +0100 Subject: [PATCH 02/15] Implement redirect for user profile --- webapp/pages/profile/{ => _id}/_slug.vue | 0 webapp/pages/profile/_id/index.vue | 46 ++++++++++++++++++++++++ webapp/pages/profile/index.vue | 8 ----- 3 files changed, 46 insertions(+), 8 deletions(-) rename webapp/pages/profile/{ => _id}/_slug.vue (100%) create mode 100644 webapp/pages/profile/_id/index.vue delete mode 100644 webapp/pages/profile/index.vue diff --git a/webapp/pages/profile/_slug.vue b/webapp/pages/profile/_id/_slug.vue similarity index 100% rename from webapp/pages/profile/_slug.vue rename to webapp/pages/profile/_id/_slug.vue diff --git a/webapp/pages/profile/_id/index.vue b/webapp/pages/profile/_id/index.vue new file mode 100644 index 000000000..78e16f8fb --- /dev/null +++ b/webapp/pages/profile/_id/index.vue @@ -0,0 +1,46 @@ + diff --git a/webapp/pages/profile/index.vue b/webapp/pages/profile/index.vue deleted file mode 100644 index 7135a2c3d..000000000 --- a/webapp/pages/profile/index.vue +++ /dev/null @@ -1,8 +0,0 @@ - From 16e60e540f1bd511c89b7667e20800747516de68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Mon, 25 Mar 2019 21:00:22 +0100 Subject: [PATCH 03/15] Fix typo Cypress tests currently fail because we cannot override `slug` in factories. --- cypress/integration/identifier/PersistentLinks.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cypress/integration/identifier/PersistentLinks.feature b/cypress/integration/identifier/PersistentLinks.feature index b4a55cee3..1095c6c72 100644 --- a/cypress/integration/identifier/PersistentLinks.feature +++ b/cypress/integration/identifier/PersistentLinks.feature @@ -12,8 +12,8 @@ Feature: Persistent Links Background: Given we have the following user accounts: - | id | name | slug | - | MHNqce98y1 | Stepen Hawking | thehawk | + | id | name | slug | + | MHNqce98y1 | Stephen Hawking | thehawk | And we have the following posts in our database: | id | title | slug | | bWBjpkTKZp | 101 Essays that will change the way you think | 101-essays | From 51cbc65f4b349ca7eef20cc31d2768749efd213b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Mon, 25 Mar 2019 23:27:00 +0100 Subject: [PATCH 04/15] Rename `profile-id` to `profile-id-slug` route --- cypress/integration/common/report.js | 2 +- webapp/components/User.vue | 6 +++--- webapp/layouts/default.vue | 2 +- webapp/pages/moderation/index.vue | 10 +++++----- webapp/pages/profile/_id/_slug.vue | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cypress/integration/common/report.js b/cypress/integration/common/report.js index 12f1b326f..e3d3f3975 100644 --- a/cypress/integration/common/report.js +++ b/cypress/integration/common/report.js @@ -71,7 +71,7 @@ When('I click on the author', () => { }) When('I report the author', () => { - cy.get('.page-name-profile-slug').then(() => { + cy.get('.page-name-profile-id-slug').then(() => { invokeReportOnElement('.ds-card').then(() => { cy.get('button') .contains('Send') diff --git a/webapp/components/User.vue b/webapp/components/User.vue index 1c78b34cc..dd176a67d 100644 --- a/webapp/components/User.vue +++ b/webapp/components/User.vue @@ -153,9 +153,9 @@ export default { return count }, userLink() { - const { slug } = this.user - if (!slug) return '' - return { name: 'profile-slug', params: { slug } } + const { id, slug } = this.user + if (!(id && slug)) return '' + return { name: 'profile-id-slug', params: { slug, id } } } } } diff --git a/webapp/layouts/default.vue b/webapp/layouts/default.vue index bdb41f8b2..f749fda69 100644 --- a/webapp/layouts/default.vue +++ b/webapp/layouts/default.vue @@ -39,7 +39,7 @@ >
- + {{ scope.row.user.name | truncate(50) }}
@@ -69,7 +69,7 @@ slot="submitter" slot-scope="scope" > - + {{ scope.row.submitter.name }} @@ -79,19 +79,19 @@ > {{ scope.row.post.disabledBy.name | truncate(50) }} {{ scope.row.comment.disabledBy.name | truncate(50) }} {{ scope.row.user.disabledBy.name | truncate(50) }} diff --git a/webapp/pages/profile/_id/_slug.vue b/webapp/pages/profile/_id/_slug.vue index 76011f456..a3b10529e 100644 --- a/webapp/pages/profile/_id/_slug.vue +++ b/webapp/pages/profile/_id/_slug.vue @@ -423,7 +423,7 @@ export default { border: #fff 5px solid; } -.page-name-profile-slug { +.page-name-profile-id-slug { .ds-flex-item:first-child .content-menu { position: absolute; top: $space-x-small; From b79ae683186125458e8904b5acfd8e6199c00d3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Mon, 25 Mar 2019 23:31:47 +0100 Subject: [PATCH 05/15] User factory can override slug --- backend/src/seed/factories/users.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/src/seed/factories/users.js b/backend/src/seed/factories/users.js index 491b3f9e1..9fe957515 100644 --- a/backend/src/seed/factories/users.js +++ b/backend/src/seed/factories/users.js @@ -5,6 +5,7 @@ export default function create (params) { const { id = uuid(), name = faker.name.findName(), + slug = '', email = faker.internet.email(), password = '1234', role = 'user', @@ -19,6 +20,7 @@ export default function create (params) { CreateUser( id: "${id}", name: "${name}", + slug: "${slug}", password: "${password}", email: "${email}", avatar: "${avatar}", @@ -29,6 +31,7 @@ export default function create (params) { ) { id name + slug email avatar role From 203f2091de445d7f13136d158f617061bdc6f726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Tue, 26 Mar 2019 14:28:55 +0100 Subject: [PATCH 06/15] Implement `id takes precedence over slug` --- .../pages/profile/{_id/index.vue => _id.vue} | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) rename webapp/pages/profile/{_id/index.vue => _id.vue} (51%) diff --git a/webapp/pages/profile/_id/index.vue b/webapp/pages/profile/_id.vue similarity index 51% rename from webapp/pages/profile/_id/index.vue rename to webapp/pages/profile/_id.vue index 78e16f8fb..eee8d610a 100644 --- a/webapp/pages/profile/_id/index.vue +++ b/webapp/pages/profile/_id.vue @@ -1,3 +1,7 @@ + + diff --git a/webapp/pages/post/_slug/index.vue b/webapp/pages/post/_id/_slug/index.vue similarity index 100% rename from webapp/pages/post/_slug/index.vue rename to webapp/pages/post/_id/_slug/index.vue diff --git a/webapp/pages/post/_slug/more-info.vue b/webapp/pages/post/_id/_slug/more-info.vue similarity index 100% rename from webapp/pages/post/_slug/more-info.vue rename to webapp/pages/post/_id/_slug/more-info.vue diff --git a/webapp/pages/post/_slug/take-action.vue b/webapp/pages/post/_id/_slug/take-action.vue similarity index 100% rename from webapp/pages/post/_slug/take-action.vue rename to webapp/pages/post/_id/_slug/take-action.vue diff --git a/webapp/pages/post/_slug.vue b/webapp/pages/post/_slug.vue deleted file mode 100644 index d4a233f0f..000000000 --- a/webapp/pages/post/_slug.vue +++ /dev/null @@ -1,54 +0,0 @@ - - - diff --git a/webapp/pages/profile/_id.vue b/webapp/pages/profile/_id.vue index eee8d610a..ad9772358 100644 --- a/webapp/pages/profile/_id.vue +++ b/webapp/pages/profile/_id.vue @@ -23,7 +23,6 @@ const querySlug = gql` ` export default { - layout: 'blank', async asyncData(context) { const { params: { id, slug }, From 63d928e12e918a080d644b55ada3fc412b35ad1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Tue, 26 Mar 2019 16:21:39 +0100 Subject: [PATCH 08/15] Change route `post-slug` to `post-id-slug` And query `slug` and `id` everywhere --- webapp/components/ContributionForm.vue | 4 ++-- webapp/components/PostCard.vue | 4 ++-- webapp/graphql/ModerationListQuery.js | 14 ++++++++++++-- webapp/graphql/UserProfileQuery.js | 6 ++++-- webapp/layouts/default.vue | 4 ++-- webapp/pages/index.vue | 4 ++-- webapp/pages/moderation/index.vue | 4 ++-- webapp/pages/post/_id/_slug/index.vue | 2 +- 8 files changed, 27 insertions(+), 15 deletions(-) diff --git a/webapp/components/ContributionForm.vue b/webapp/components/ContributionForm.vue index cf7c28ece..3ef041569 100644 --- a/webapp/components/ContributionForm.vue +++ b/webapp/components/ContributionForm.vue @@ -111,8 +111,8 @@ export default { const result = res.data[this.id ? 'UpdatePost' : 'CreatePost'] this.$router.push({ - name: 'post-slug', - params: { slug: result.slug } + name: 'post-id-slug', + params: { id: result.id, slug: result.slug } }) }) .catch(err => { diff --git a/webapp/components/PostCard.vue b/webapp/components/PostCard.vue index 8f534f6ff..767835f74 100644 --- a/webapp/components/PostCard.vue +++ b/webapp/components/PostCard.vue @@ -106,8 +106,8 @@ export default { methods: { href(post) { return this.$router.resolve({ - name: 'post-slug', - params: { slug: post.slug } + name: 'post-id-slug', + params: { id: post.id, slug: post.slug } }).href } } diff --git a/webapp/graphql/ModerationListQuery.js b/webapp/graphql/ModerationListQuery.js index d8105e388..4e3927bdd 100644 --- a/webapp/graphql/ModerationListQuery.js +++ b/webapp/graphql/ModerationListQuery.js @@ -9,43 +9,52 @@ export default app => { type createdAt submitter { + id disabled deleted name slug } user { + id name slug disabled deleted disabledBy { + id slug name + disabled + deleted } } comment { contentExcerpt author { + id name slug disabled deleted } post { + id disabled deleted title slug } disabledBy { + id + slug disabled deleted - slug name } } post { + id title slug disabled @@ -57,9 +66,10 @@ export default app => { slug } disabledBy { + id + slug disabled deleted - slug name } } diff --git a/webapp/graphql/UserProfileQuery.js b/webapp/graphql/UserProfileQuery.js index 683f0e3ac..f0d7720ae 100644 --- a/webapp/graphql/UserProfileQuery.js +++ b/webapp/graphql/UserProfileQuery.js @@ -6,6 +6,7 @@ export default app => { query User($slug: String!, $first: Int, $offset: Int) { User(slug: $slug) { id + slug name avatar about @@ -27,8 +28,8 @@ export default app => { followingCount following(first: 7) { id - name slug + name avatar disabled deleted @@ -49,10 +50,10 @@ export default app => { followedByCurrentUser followedBy(first: 7) { id + slug name disabled deleted - slug avatar followedByCount followedByCurrentUser @@ -87,6 +88,7 @@ export default app => { } author { id + slug avatar name disabled diff --git a/webapp/layouts/default.vue b/webapp/layouts/default.vue index f749fda69..991662350 100644 --- a/webapp/layouts/default.vue +++ b/webapp/layouts/default.vue @@ -182,8 +182,8 @@ export default { goToPost(item) { this.$nextTick(() => { this.$router.push({ - name: 'post-slug', - params: { slug: item.slug } + name: 'post-id-slug', + params: { id: item.id, slug: item.slug } }) }) }, diff --git a/webapp/pages/index.vue b/webapp/pages/index.vue index e28d6b2c3..ee824eb59 100644 --- a/webapp/pages/index.vue +++ b/webapp/pages/index.vue @@ -64,8 +64,8 @@ export default { }, href(post) { return this.$router.resolve({ - name: 'post-slug', - params: { slug: post.slug } + name: 'post-id-slug', + params: { id: post.id, slug: post.slug } }).href }, showMoreContributions() { diff --git a/webapp/pages/moderation/index.vue b/webapp/pages/moderation/index.vue index 5d9ab1eb0..fc5d1fbe6 100644 --- a/webapp/pages/moderation/index.vue +++ b/webapp/pages/moderation/index.vue @@ -14,7 +14,7 @@ slot-scope="scope" >
- + {{ scope.row.post.title | truncate(50) }}
- + {{ scope.row.comment.contentExcerpt | truncate(50) }}