From 2aa64c075d42ca402b9bcbafe4fc5ecf8cfb9c89 Mon Sep 17 00:00:00 2001
From: Colby Gutierrez-Kraybill <colby+github@kraybill.com>
Date: Fri, 18 Apr 2025 18:28:05 -0400
Subject: [PATCH] hrefs for /users/:username without a trailing / lead to
 django kicking back a redirect to /users/:username/ This activity leads to
 scratch-www-production having 40-60% redirects. It would be useful to clear
 this noise up for SRE related operations.

---
 .../become-a-scratcher/become-a-scratcher.jsx |  2 +-
 src/views/contact-us/contact-us.jsx           |  2 +-
 .../messages/message-rows/comment-message.jsx |  2 +-
 .../message-rows/favorite-project.jsx         |  2 +-
 .../messages/message-rows/love-project.jsx    |  2 +-
 .../messages/message-rows/remix-project.jsx   |  2 +-
 .../splash/activity-rows/favorite-project.jsx |  2 +-
 .../splash/activity-rows/remix-project.jsx    |  2 +-
 .../splash/activity-rows/share-project.jsx    |  2 +-
 src/views/studio/studio-activity.jsx          | 24 +++++++++----------
 src/views/studio/studio-member-tile.jsx       |  2 +-
 src/views/studio/studio-project-tile.jsx      |  2 +-
 12 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/src/views/become-a-scratcher/become-a-scratcher.jsx b/src/views/become-a-scratcher/become-a-scratcher.jsx
index 6c93c29c4..42db63607 100644
--- a/src/views/become-a-scratcher/become-a-scratcher.jsx
+++ b/src/views/become-a-scratcher/become-a-scratcher.jsx
@@ -67,7 +67,7 @@ const OnboardingHeader = ({user, section, secondary}) => {
                         className="profile-page-image"
                         src="/images/onboarding/profile-page-become-a-scratcher-button.svg"
                     />
-                    <a href={`/users/${user.username}`}>
+                    <a href={`/users/${user.username}/`}>
                         <Button>
                             <FormattedMessage
                                 id={'becomeAScratcher.buttons.backToProfile'}
diff --git a/src/views/contact-us/contact-us.jsx b/src/views/contact-us/contact-us.jsx
index 9e022e4cf..59e9d5667 100644
--- a/src/views/contact-us/contact-us.jsx
+++ b/src/views/contact-us/contact-us.jsx
@@ -31,7 +31,7 @@ class ContactUs extends React.Component {
         } else if (query.indexOf('profile=') !== -1) {
             scratchId = query.match(/profile=([a-zA-Z0-9-_]+)/)[1];
             this.state.subject = `Issue reported with profile ${scratchId}`;
-            this.state.body = `https://scratch.mit.edu/users/${scratchId}`;
+            this.state.body = `https://scratch.mit.edu/users/${scratchId}/`;
         } else if (query.indexOf('confirmation=') !== -1) {
             this.state.subject = 'Problem with email confirmation';
         }
diff --git a/src/views/messages/message-rows/comment-message.jsx b/src/views/messages/message-rows/comment-message.jsx
index 0d4f91966..1f36cff50 100644
--- a/src/views/messages/message-rows/comment-message.jsx
+++ b/src/views/messages/message-rows/comment-message.jsx
@@ -161,7 +161,7 @@ class CommentMessage extends React.Component {
                     {this.getMessageText(this.props.objectType, this.props.commentee)}
                 </p>
                 <FlexRow className="mod-comment-message">
-                    <a href={`/users/${this.props.actorUsername}`}>
+                    <a href={`/users/${this.props.actorUsername}/`}>
                         <img
                             alt={`${this.props.actorUsername}'s avatar`}
                             className="comment-message-info-img"
diff --git a/src/views/messages/message-rows/favorite-project.jsx b/src/views/messages/message-rows/favorite-project.jsx
index b75534eaf..48e488e56 100644
--- a/src/views/messages/message-rows/favorite-project.jsx
+++ b/src/views/messages/message-rows/favorite-project.jsx
@@ -21,7 +21,7 @@ const FavoriteProjectMessage = props => (
                 profileLink: (
                     <a
                         className="social-messages-profile-link"
-                        href={`/users/${props.actorUsername}`}
+                        href={`/users/${props.actorUsername}/`}
                     >
                         {props.actorUsername}
                     </a>
diff --git a/src/views/messages/message-rows/love-project.jsx b/src/views/messages/message-rows/love-project.jsx
index 3d5409aff..8d154e819 100644
--- a/src/views/messages/message-rows/love-project.jsx
+++ b/src/views/messages/message-rows/love-project.jsx
@@ -21,7 +21,7 @@ const LoveProjectMessage = props => (
                 profileLink: (
                     <a
                         className="social-messages-profile-link"
-                        href={`/users/${props.actorUsername}`}
+                        href={`/users/${props.actorUsername}/`}
                     >
                         {props.actorUsername}
                     </a>
diff --git a/src/views/messages/message-rows/remix-project.jsx b/src/views/messages/message-rows/remix-project.jsx
index 356e6f6b5..c0639b4c2 100644
--- a/src/views/messages/message-rows/remix-project.jsx
+++ b/src/views/messages/message-rows/remix-project.jsx
@@ -21,7 +21,7 @@ const RemixProjectMessage = props => (
                 profileLink: (
                     <a
                         className="social-messages-profile-link"
-                        href={`/users/${props.actorUsername}`}
+                        href={`/users/${props.actorUsername}/`}
                     >
                         {props.actorUsername}
                     </a>
diff --git a/src/views/splash/activity-rows/favorite-project.jsx b/src/views/splash/activity-rows/favorite-project.jsx
index 8775fd024..e7b073658 100644
--- a/src/views/splash/activity-rows/favorite-project.jsx
+++ b/src/views/splash/activity-rows/favorite-project.jsx
@@ -18,7 +18,7 @@ const FavoriteProjectMessage = props => (
             id="messages.favoriteText"
             values={{
                 profileLink: (
-                    <a href={`/users/${props.actorUsername}`}>
+                    <a href={`/users/${props.actorUsername}/`}>
                         {props.actorUsername}
                     </a>
                 ),
diff --git a/src/views/splash/activity-rows/remix-project.jsx b/src/views/splash/activity-rows/remix-project.jsx
index 67b8b1f4b..160008d6a 100644
--- a/src/views/splash/activity-rows/remix-project.jsx
+++ b/src/views/splash/activity-rows/remix-project.jsx
@@ -18,7 +18,7 @@ const RemixProjectMessage = props => (
             id="messages.remixText"
             values={{
                 profileLink: (
-                    <a href={`/users/${props.actorUsername}`}>
+                    <a href={`/users/${props.actorUsername}/`}>
                         {props.actorUsername}
                     </a>
                 ),
diff --git a/src/views/splash/activity-rows/share-project.jsx b/src/views/splash/activity-rows/share-project.jsx
index 71ed56ef1..786e91c67 100644
--- a/src/views/splash/activity-rows/share-project.jsx
+++ b/src/views/splash/activity-rows/share-project.jsx
@@ -18,7 +18,7 @@ const ShareProjectMessage = props => (
             id="messages.shareText"
             values={{
                 profileLink: (
-                    <a href={`/users/${props.actorUsername}`}>
+                    <a href={`/users/${props.actorUsername}/`}>
                         {props.actorUsername}
                     </a>
                 ),
diff --git a/src/views/studio/studio-activity.jsx b/src/views/studio/studio-activity.jsx
index 9a17377a7..8fd608cd1 100644
--- a/src/views/studio/studio-activity.jsx
+++ b/src/views/studio/studio-activity.jsx
@@ -27,7 +27,7 @@ const getComponentForItem = item => {
                     id="studio.activityAddProjectToStudio"
                     values={{
                         profileLink: (
-                            <a href={`/users/${item.actor_username}`}>
+                            <a href={`/users/${item.actor_username}/`}>
                                 {item.actor_username}
                             </a>
                         ),
@@ -53,7 +53,7 @@ const getComponentForItem = item => {
                     id="studio.activityRemoveProjectStudio"
                     values={{
                         profileLink: (
-                            <a href={`/users/${item.actor_username}`}>
+                            <a href={`/users/${item.actor_username}/`}>
                                 {item.actor_username}
                             </a>
                         ),
@@ -79,7 +79,7 @@ const getComponentForItem = item => {
                     id="studio.activityUpdateStudio"
                     values={{
                         profileLink: (
-                            <a href={`/users/${item.actor_username}`}>
+                            <a href={`/users/${item.actor_username}/`}>
                                 {item.actor_username}
                             </a>
                         )
@@ -101,12 +101,12 @@ const getComponentForItem = item => {
                     values={{
                         // Beware, DB seems to think actor is new curator and username is inviter
                         newCuratorProfileLink: (
-                            <a href={`/users/${item.actor_username}`}>
+                            <a href={`/users/${item.actor_username}/`}>
                                 {item.actor_username}
                             </a>
                         ),
                         inviterProfileLink: (
-                            <a href={`/users/${item.username}`}>
+                            <a href={`/users/${item.username}/`}>
                                 {item.username}
                             </a>
                         )
@@ -127,12 +127,12 @@ const getComponentForItem = item => {
                     id="studio.activityRemoveCurator"
                     values={{
                         removedProfileLink: (
-                            <a href={`/users/${item.username}`}>
+                            <a href={`/users/${item.username}/`}>
                                 {item.username}
                             </a>
                         ),
                         removerProfileLink: (
-                            <a href={`/users/${item.actor_username}`}>
+                            <a href={`/users/${item.actor_username}/`}>
                                 {item.actor_username}
                             </a>
                         )
@@ -153,12 +153,12 @@ const getComponentForItem = item => {
                     id="studio.activityBecomeOwner"
                     values={{
                         promotedProfileLink: (
-                            <a href={`/users/${item.recipient_username}`}>
+                            <a href={`/users/${item.recipient_username}/`}>
                                 {item.recipient_username}
                             </a>
                         ),
                         promotorProfileLink: (
-                            <a href={`/users/${item.actor_username}`}>
+                            <a href={`/users/${item.actor_username}/`}>
                                 {item.actor_username}
                             </a>
                         )
@@ -180,7 +180,7 @@ const getComponentForItem = item => {
                         id="studio.activityBecomeHostAdminActor"
                         values={{
                             newHostProfileLink: (
-                                <a href={`/users/${item.recipient_username}`}>
+                                <a href={`/users/${item.recipient_username}/`}>
                                     {item.recipient_username}
                                 </a>
                             )
@@ -190,12 +190,12 @@ const getComponentForItem = item => {
                         id="studio.activityBecomeHost"
                         values={{
                             newHostProfileLink: (
-                                <a href={`/users/${item.recipient_username}`}>
+                                <a href={`/users/${item.recipient_username}/`}>
                                     {item.recipient_username}
                                 </a>
                             ),
                             actorProfileLink: (
-                                <a href={`/users/${item.actor_username}`}>
+                                <a href={`/users/${item.actor_username}/`}>
                                     {item.actor_username}
                                 </a>
                             )
diff --git a/src/views/studio/studio-member-tile.jsx b/src/views/studio/studio-member-tile.jsx
index 13c94a3e4..5a546d996 100644
--- a/src/views/studio/studio-member-tile.jsx
+++ b/src/views/studio/studio-member-tile.jsx
@@ -37,7 +37,7 @@ const StudioMemberTile = ({
     const [transferHostModalOpen, setTransferHostModalOpen] = useState(false);
     const [managerLimitReached, setManagerLimitReached] = useState(false);
     const {errorAlert, successAlert} = useAlertContext();
-    const userUrl = `/users/${username}`;
+    const userUrl = `/users/${username}/`;
     return (
         <div className="studio-member-tile">
             <a href={userUrl}>
diff --git a/src/views/studio/studio-project-tile.jsx b/src/views/studio/studio-project-tile.jsx
index 788f028db..7f8aab1e7 100644
--- a/src/views/studio/studio-project-tile.jsx
+++ b/src/views/studio/studio-project-tile.jsx
@@ -18,7 +18,7 @@ const StudioProjectTile = ({
 }) => {
     const [submitting, setSubmitting] = useState(false);
     const projectUrl = `/projects/${id}`;
-    const userUrl = `/users/${username}`;
+    const userUrl = `/users/${username}/`;
     const {errorAlert} = useContext(AlertContext);
     return (
         <div className="studio-project-tile">