diff --git a/pkg/config/admin_scopes.go b/pkg/config/admin_scopes.go index 457bd23..aa1f813 100644 --- a/pkg/config/admin_scopes.go +++ b/pkg/config/admin_scopes.go @@ -6,11 +6,9 @@ const ( // - Chat: have operator controls in the chat room // - Forum: ability to edit and delete user posts // - Photo: omniscient view of all gallery photos, can edit/delete photos - // - Inner circle: ability to remove users from it - ScopeChatModerator = "social.moderator.chat" - ScopeForumModerator = "social.moderator.forum" - ScopePhotoModerator = "social.moderator.photo" - ScopeCircleModerator = "social.moderator.inner-circle" + ScopeChatModerator = "social.moderator.chat" + ScopeForumModerator = "social.moderator.forum" + ScopePhotoModerator = "social.moderator.photo" // Certification photo management // - Approve: ability to respond to pending certification pics @@ -48,9 +46,6 @@ const ( // Admins with this scope can not be blocked by users. ScopeUnblockable = "admin.unblockable" - // Special scope to mark an admin automagically in the Inner Circle - ScopeIsInnerCircle = "admin.override.inner-circle" - // The global wildcard scope gets all available permissions. ScopeSuperuser = "*" ) @@ -60,7 +55,6 @@ var AdminScopeDescriptions = map[string]string{ ScopeChatModerator: "Have operator controls in the chat room (can mark cameras as explicit, or kick/ban people from chat).", ScopeForumModerator: "Ability to moderate the forum (edit or delete posts).", ScopePhotoModerator: "Ability to moderate photo galleries (can see all private or friends-only photos, and edit or delete them).", - ScopeCircleModerator: "Ability to remove members from the inner circle.", ScopeCertificationApprove: "Ability to see pending certification pictures and approve or reject them.", ScopeCertificationList: "Ability to see existing certification pictures that have already been approved or rejected.", ScopeCertificationView: "Ability to see and double check a specific user's certification picture on demand.", @@ -78,7 +72,6 @@ var AdminScopeDescriptions = map[string]string{ ScopeChangeLog: "Ability to see website change logs (e.g. history of a certification photo, gallery photo settings, etc.)", ScopeUserNotes: "Ability to see all notes written about a user, or to see all notes written by admins.", ScopeUnblockable: "This admin can not be added to user block lists.", - ScopeIsInnerCircle: "This admin is automatically part of the inner circle.", ScopeSuperuser: "This admin has access to ALL admin features on the website.", } @@ -94,7 +87,6 @@ func ListAdminScopes() []string { ScopeChatModerator, ScopeForumModerator, ScopePhotoModerator, - ScopeCircleModerator, ScopeCertificationApprove, ScopeCertificationList, ScopeCertificationView, @@ -112,7 +104,6 @@ func ListAdminScopes() []string { ScopeChangeLog, ScopeUserNotes, ScopeUnblockable, - ScopeIsInnerCircle, } } diff --git a/pkg/config/config.go b/pkg/config/config.go index 7bf1235..127b07f 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -107,9 +107,6 @@ const ( PhotoQuotaUncertified = 6 PhotoQuotaCertified = 100 - // Min number of public photos for inner circle members to see the prompt to invite. - InnerCircleMinimumPublicPhotos = 5 - // Rate limit for too many Site Gallery pictures. // Some users sign up and immediately max out their gallery and spam // the Site Gallery page. These limits can ensure only a few Site Gallery diff --git a/pkg/config/enum.go b/pkg/config/enum.go index 63b33bd..f4a8284 100644 --- a/pkg/config/enum.go +++ b/pkg/config/enum.go @@ -106,7 +106,6 @@ var ( // Default forum categories for forum landing page. ForumCategories = []string{ "Rules and Announcements", - "The Inner Circle", "Nudists", "Exhibitionists", "Photo Boards", diff --git a/pkg/controller/account/inner_circle.go b/pkg/controller/account/inner_circle.go deleted file mode 100644 index 582d1dc..0000000 --- a/pkg/controller/account/inner_circle.go +++ /dev/null @@ -1,216 +0,0 @@ -package account - -import ( - "fmt" - "net/http" - - "code.nonshy.com/nonshy/website/pkg/config" - "code.nonshy.com/nonshy/website/pkg/log" - "code.nonshy.com/nonshy/website/pkg/models" - "code.nonshy.com/nonshy/website/pkg/session" - "code.nonshy.com/nonshy/website/pkg/templates" -) - -// InnerCircle is the landing page for inner circle members only. -func InnerCircle() http.HandlerFunc { - tmpl := templates.Must("account/inner_circle.html") - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - currentUser, err := session.CurrentUser(r) - if err != nil || !currentUser.IsInnerCircle() { - templates.NotFoundPage(w, r) - return - } - - var vars = map[string]interface{}{ - "InnerCircleMinimumPublicPhotos": config.InnerCircleMinimumPublicPhotos, - } - - if err := tmpl.Execute(w, r, vars); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - }) -} - -// InviteCircle is the landing page to invite a user into the circle. -func InviteCircle() http.HandlerFunc { - tmpl := templates.Must("account/invite_circle.html") - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - currentUser, err := session.CurrentUser(r) - if err != nil || !currentUser.IsInnerCircle() { - templates.NotFoundPage(w, r) - return - } - - // Invite whom? - username := r.FormValue("to") - user, err := models.FindUser(username) - if err != nil { - templates.NotFoundPage(w, r) - return - } - - if currentUser.ID == user.ID && currentUser.InnerCircle { - session.FlashError(w, r, "You are already part of the inner circle.") - templates.Redirect(w, "/inner-circle") - return - } - - // Any blocking? - if models.IsBlocking(currentUser.ID, user.ID) && !currentUser.IsAdmin { - session.FlashError(w, r, "You are blocked from inviting this user to the circle.") - templates.Redirect(w, "/inner-circle") - return - } - - // POSTing? - if r.Method == http.MethodPost { - var ( - confirm = r.FormValue("intent") == "confirm" - ) - - if !confirm { - templates.Redirect(w, "/u/"+username) - return - } - - // Add them! - if err := models.AddToInnerCircle(user); err != nil { - session.FlashError(w, r, "Couldn't add to the inner circle: %s", err) - } else { - session.Flash(w, r, "%s has been added to the inner circle!", user.Username) - } - - log.Info("InnerCircle: %s adds %s to the inner circle", currentUser.Username, user.Username) - - templates.Redirect(w, "/u/"+user.Username+"/photos") - return - } - - var vars = map[string]interface{}{ - "User": user, - } - if err := tmpl.Execute(w, r, vars); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - }) -} - -// RemoveCircle is the admin-only page to remove a member from the circle. -func RemoveCircle() http.HandlerFunc { - tmpl := templates.Must("account/remove_circle.html") - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - currentUser, err := session.CurrentUser(r) - if err != nil || !currentUser.IsInnerCircle() { - templates.NotFoundPage(w, r) - return - } - - // Remove whom? - username := r.FormValue("to") - user, err := models.FindUser(username) - if err != nil { - templates.NotFoundPage(w, r) - return - } - - // POSTing? - if r.Method == http.MethodPost { - var ( - confirm = r.FormValue("intent") == "confirm" - ) - - if !confirm { - templates.Redirect(w, "/u/"+username) - return - } - - // Admin (with the correct scope): remove them now. - if currentUser.HasAdminScope(config.ScopeCircleModerator) { - if err := models.RemoveFromInnerCircle(user); err != nil { - session.FlashError(w, r, "Couldn't remove from the inner circle: %s", err) - } - - session.Flash(w, r, "%s has been removed from the inner circle!", user.Username) - } else { - // Non-admin user: request removal only. - fb := &models.Feedback{ - Intent: "report.circle", - Subject: "Inner Circle Removal Request", - TableName: "users", - TableID: user.ID, - Message: fmt.Sprintf( - "An inner circle member has flagged that **%s** no longer qualifies to be a part of the inner circle and should be removed.", - user.Username, - ), - } - - if err := models.CreateFeedback(fb); err != nil { - session.FlashError(w, r, "Couldn't create admin notification: %s", err) - } else { - session.Flash(w, r, "A request to remove %s from the inner circle has been sent to the site admin.", user.Username) - } - } - - templates.Redirect(w, "/u/"+user.Username) - return - } - - var vars = map[string]interface{}{ - "User": user, - } - if err := tmpl.Execute(w, r, vars); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - }) -} - -// LeaveCircle allows users to remove themself from the circle. -func LeaveCircle() http.HandlerFunc { - tmpl := templates.Must("account/leave_circle.html") - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - currentUser, err := session.CurrentUser(r) - if err != nil || !currentUser.IsInnerCircle() { - templates.NotFoundPage(w, r) - return - } - - // Submitting the form? - if r.Method == http.MethodPost { - var ( - confirm = r.PostFormValue("confirm") == "true" - dontReinvite = r.PostFormValue("dont_reinvite") == "true" - ) - - if !confirm { - templates.Redirect(w, r.URL.Path) - return - } - - // Remove them from the circle now. - if err := models.RemoveFromInnerCircle(currentUser); err != nil { - session.FlashError(w, r, "Error updating your inner circle status: %s", err) - templates.Redirect(w, r.URL.Path) - return - } - - // Confirmation message, + don't reinvite again? - if dontReinvite { - currentUser.SetProfileField("inner_circle_optout", "true") - session.Flash(w, r, "You have been removed from the inner circle, and you WILL NOT be invited again in the future.") - } else { - session.Flash(w, r, "You have been removed from the inner circle.") - } - - templates.Redirect(w, "/me") - return - } - - if err := tmpl.Execute(w, r, nil); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - }) -} diff --git a/pkg/controller/account/search.go b/pkg/controller/account/search.go index a399c22..c592c87 100644 --- a/pkg/controller/account/search.go +++ b/pkg/controller/account/search.go @@ -159,7 +159,6 @@ func Search() http.HandlerFunc { Certified: certifiedOnly, NearCity: city, NotCertified: isCertified == "false", - InnerCircle: isCertified == "circle", ShyAccounts: isCertified == "shy", IsBanned: isCertified == "banned", IsDisabled: isCertified == "disabled", diff --git a/pkg/controller/admin/feedback.go b/pkg/controller/admin/feedback.go index 77be3a6..c9b5542 100644 --- a/pkg/controller/admin/feedback.go +++ b/pkg/controller/admin/feedback.go @@ -50,12 +50,7 @@ func Feedback() http.HandlerFunc { if err != nil { session.FlashError(w, r, "Couldn't visit user %d: %s", fb.TableID, err) } else { - // If this is an "inner circle removal" report, go to their gallery and filter pics by Public. - if fb.Intent == "report.circle" { - templates.Redirect(w, "/u/"+user.Username+"/photos?visibility=public") - } else { - templates.Redirect(w, "/u/"+user.Username) - } + templates.Redirect(w, "/u/"+user.Username) return } case "photos": diff --git a/pkg/controller/chat/chat.go b/pkg/controller/chat/chat.go index ca5f5c5..8afa506 100644 --- a/pkg/controller/chat/chat.go +++ b/pkg/controller/chat/chat.go @@ -104,8 +104,6 @@ func Landing() http.HandlerFunc { avatar = "/static/img/shy-private.png" case models.PhotoFriends: avatar = "/static/img/shy-friends.png" - case models.PhotoInnerCircle: - avatar = "/static/img/shy-secret.png" } // Country flag emoji. @@ -125,7 +123,6 @@ func Landing() http.HandlerFunc { // Create the JWT claims. claims := Claims{ IsAdmin: currentUser.HasAdminScope(config.ScopeChatModerator), - VIP: currentUser.IsInnerCircle(), Avatar: avatar, ProfileURL: "/u/" + currentUser.Username, Nickname: currentUser.NameOrUsername(), diff --git a/pkg/controller/forum/add_edit.go b/pkg/controller/forum/add_edit.go index 939d3df..053d22a 100644 --- a/pkg/controller/forum/add_edit.go +++ b/pkg/controller/forum/add_edit.go @@ -64,7 +64,6 @@ func AddEdit() http.HandlerFunc { isExplicit = r.PostFormValue("explicit") == "true" isPrivileged = r.PostFormValue("privileged") == "true" isPermitPhotos = r.PostFormValue("permit_photos") == "true" - isInnerCircle = r.PostFormValue("inner_circle") == "true" isPrivate = r.PostFormValue("private") == "true" ) @@ -84,7 +83,6 @@ func AddEdit() http.HandlerFunc { models.NewFieldDiff("Explicit", forum.Explicit, isExplicit), models.NewFieldDiff("Privileged", forum.Privileged, isPrivileged), models.NewFieldDiff("PermitPhotos", forum.PermitPhotos, isPermitPhotos), - models.NewFieldDiff("InnerCircle", forum.InnerCircle, isInnerCircle), models.NewFieldDiff("Private", forum.Private, isPrivate), } @@ -94,7 +92,6 @@ func AddEdit() http.HandlerFunc { forum.Explicit = isExplicit forum.Privileged = isPrivileged forum.PermitPhotos = isPermitPhotos - forum.InnerCircle = isInnerCircle forum.Private = isPrivate // Save it. @@ -131,7 +128,6 @@ func AddEdit() http.HandlerFunc { Explicit: isExplicit, Privileged: isPrivileged, PermitPhotos: isPermitPhotos, - InnerCircle: isInnerCircle, Private: isPrivate, } @@ -149,7 +145,6 @@ func AddEdit() http.HandlerFunc { "* Explicit: %v\n"+ "* Privileged: %v\n"+ "* Photos: %v\n"+ - "* Inner Circle: %v\n"+ "* Private: %v", forum.Category, forum.Title, @@ -158,7 +153,6 @@ func AddEdit() http.HandlerFunc { forum.Explicit, forum.Privileged, forum.PermitPhotos, - forum.InnerCircle, forum.Private, )) diff --git a/pkg/controller/forum/forum.go b/pkg/controller/forum/forum.go index 045db0d..71bd594 100644 --- a/pkg/controller/forum/forum.go +++ b/pkg/controller/forum/forum.go @@ -35,12 +35,6 @@ func Forum() http.HandlerFunc { return } - // Is it an inner circle forum? - if forum.InnerCircle && !currentUser.IsInnerCircle() { - templates.NotFoundPage(w, r) - return - } - // Is it a private forum? if forum.Private && !currentUser.IsAdmin { templates.NotFoundPage(w, r) diff --git a/pkg/controller/forum/thread.go b/pkg/controller/forum/thread.go index b047f7c..29c1ced 100644 --- a/pkg/controller/forum/thread.go +++ b/pkg/controller/forum/thread.go @@ -51,12 +51,6 @@ func Thread() http.HandlerFunc { return } - // Is it an inner circle forum? - if forum.InnerCircle && !currentUser.IsInnerCircle() { - templates.NotFoundPage(w, r) - return - } - // Is it a private forum? if forum.Private && !currentUser.IsAdmin { templates.NotFoundPage(w, r) diff --git a/pkg/controller/photo/edit_delete.go b/pkg/controller/photo/edit_delete.go index ee87457..5425e40 100644 --- a/pkg/controller/photo/edit_delete.go +++ b/pkg/controller/photo/edit_delete.go @@ -83,9 +83,8 @@ func Edit() http.HandlerFunc { setProfilePic = r.FormValue("intent") == "profile-pic" crop = pphoto.ParseCropCoords(r.FormValue("crop")) - // Are we GOING private or changing to Inner Circle? + // Are we GOING private? goingPrivate = visibility == models.PhotoPrivate && visibility != photo.Visibility - goingCircle = visibility == models.PhotoInnerCircle && visibility != photo.Visibility ) if len(altText) > config.AltTextMaxLength { @@ -164,7 +163,7 @@ func Edit() http.HandlerFunc { } // If this picture has moved to Private, revoke any notification we gave about it before. - if goingPrivate || goingCircle { + if goingPrivate { log.Info("The picture is GOING PRIVATE (to %s), revoke any notifications about it", photo.Visibility) models.RemoveNotification("photos", photo.ID) } @@ -241,13 +240,6 @@ func Delete() http.HandlerFunc { } } - // Inner circle warning: if this deletion would drop them below the 5 public picture - // threshold, warn them they will be removed from the circle if they continue. - var innerCircleWarning bool - if currentUser.IsInnerCircle() && photo.Visibility == models.PhotoPublic && models.CountPublicPhotos(currentUser.ID) <= 5 { - innerCircleWarning = true - } - // Confirm deletion? if r.Method == http.MethodPost { confirm := r.PostFormValue("confirm") == "true" @@ -291,15 +283,6 @@ func Delete() http.HandlerFunc { // Log the change. models.LogDeleted(currentUser, requestUser, "photos", photo.ID, "Deleted the photo.", photo) - // Remove them from the inner circle? - if innerCircleWarning { - if err := models.RemoveFromInnerCircle(currentUser); err != nil { - session.FlashError(w, r, "Couldn't remove from the inner circle: %s", err) - } else { - session.Flash(w, r, "You have been removed from the inner circle because your count of public photos has dropped below 5.") - } - } - session.Flash(w, r, "Photo deleted!") // Maybe kick them from chat if this deletion makes them into a Shy Account. @@ -313,8 +296,7 @@ func Delete() http.HandlerFunc { } var vars = map[string]interface{}{ - "Photo": photo, - "InnerCircleWarning": innerCircleWarning, + "Photo": photo, } if err := tmpl.Execute(w, r, vars); err != nil { diff --git a/pkg/controller/photo/upload.go b/pkg/controller/photo/upload.go index 2595b61..3b6d3f9 100644 --- a/pkg/controller/photo/upload.go +++ b/pkg/controller/photo/upload.go @@ -222,15 +222,6 @@ func notifyFriendsNewPhoto(photo *models.Photo, currentUser *models.User) { notifyUserIDs = models.PrivateGranteeUserIDs(currentUser.ID) log.Info("Notify %d private grantees about the new photo by %s", len(notifyUserIDs), currentUser.Username) } - } else if photo.Visibility == models.PhotoInnerCircle { - // Inner circle members. If the pic is also Explicit, further narrow to explicit friend IDs. - if photo.Explicit { - notifyUserIDs = models.FriendIDsInCircleAreExplicit(currentUser.ID) - log.Info("Notify %d EXPLICIT circle friends about the new photo by %s", len(notifyUserIDs), currentUser.Username) - } else { - notifyUserIDs = models.FriendIDsInCircle(currentUser.ID) - log.Info("Notify %d circle friends about the new photo by %s", len(notifyUserIDs), currentUser.Username) - } } else { // Friends only: we will notify exactly the friends we selected above. notifyUserIDs = friendIDs diff --git a/pkg/controller/photo/user_gallery.go b/pkg/controller/photo/user_gallery.go index 113adbb..a9b6962 100644 --- a/pkg/controller/photo/user_gallery.go +++ b/pkg/controller/photo/user_gallery.go @@ -32,9 +32,6 @@ func UserPhotos() http.HandlerFunc { filterVisibility = r.FormValue("visibility") sort = r.FormValue("sort") sortOK bool - - // Inner circle invite view? - innerCircleInvite = r.FormValue("intent") == "inner_circle" ) // Sort options. @@ -73,11 +70,6 @@ func UserPhotos() http.HandlerFunc { isShyFrom = !isOwnPhotos && (currentUser.IsShyFrom(user) || (isShy && !areFriends)) ) - // Inner circle invite: not if we are not in the circle ourselves. - if innerCircleInvite && !currentUser.IsInnerCircle() { - innerCircleInvite = false - } - // Bail early if we are shy from this user. if isShy && isShyFrom { var vars = map[string]interface{}{ @@ -126,11 +118,6 @@ func UserPhotos() http.HandlerFunc { visibility = append(visibility, models.PhotoFriends) } - // Inner circle photos. - if currentUser.IsInnerCircle() { - visibility = append(visibility, models.PhotoInnerCircle) - } - // If we are Filtering by Visibility, ensure the target visibility is accessible to us. if filterVisibility != "" { var isOK bool @@ -220,14 +207,11 @@ func UserPhotos() http.HandlerFunc { "NoteCount": models.CountNotesAboutUser(currentUser, user), "FriendCount": models.CountFriends(user.ID), "PublicPhotoCount": models.CountPublicPhotos(user.ID), - "InnerCircleMinimumPublicPhotos": config.InnerCircleMinimumPublicPhotos, "Pager": pager, "LikeMap": likeMap, "CommentMap": commentMap, "ViewStyle": viewStyle, "ExplicitCount": explicitCount, - "InnerCircleOptOut": user.GetProfileField("inner_circle_optout") == "true", - "InnerCircleInviteView": innerCircleInvite, // Search filters "Sort": sort, diff --git a/pkg/controller/photo/view.go b/pkg/controller/photo/view.go index 7cdf654..a4ea245 100644 --- a/pkg/controller/photo/view.go +++ b/pkg/controller/photo/view.go @@ -55,12 +55,6 @@ func View() http.HandlerFunc { return } - // Is this a circle photo? - if photo.Visibility == models.PhotoInnerCircle && !currentUser.IsInnerCircle() { - templates.NotFoundPage(w, r) - return - } - // Is this user private and we're not friends? var ( areFriends = models.AreFriends(user.ID, currentUser.ID) diff --git a/pkg/models/forum.go b/pkg/models/forum.go index 3b02c3b..e9fd09a 100644 --- a/pkg/models/forum.go +++ b/pkg/models/forum.go @@ -20,7 +20,6 @@ type Forum struct { Explicit bool `gorm:"index"` Privileged bool PermitPhotos bool - InnerCircle bool `gorm:"index"` Private bool `gorm:"index"` CreatedAt time.Time UpdatedAt time.Time @@ -97,11 +96,6 @@ func PaginateForums(user *User, categories []string, pager *Pagination) ([]*Foru wheres = append(wheres, "explicit = false") } - // Hide circle forums if the user isn't in the circle. - if !user.IsInnerCircle() { - wheres = append(wheres, "inner_circle is not true") - } - // Hide private forums except for admins. if !user.IsAdmin { wheres = append(wheres, "private is not true") diff --git a/pkg/models/forum_recent.go b/pkg/models/forum_recent.go index 9f412ae..5f3beb0 100644 --- a/pkg/models/forum_recent.go +++ b/pkg/models/forum_recent.go @@ -47,11 +47,6 @@ func PaginateRecentPosts(user *User, categories []string, allComments bool, page wheres = append(wheres, "forums.explicit = false") } - // Circle membership. - if !user.IsInnerCircle() { - wheres = append(wheres, "forums.inner_circle is not true") - } - // Private forums. if !user.IsAdmin { wheres = append(wheres, "forums.private is not true") diff --git a/pkg/models/forum_search.go b/pkg/models/forum_search.go index 7906f95..e1f047d 100644 --- a/pkg/models/forum_search.go +++ b/pkg/models/forum_search.go @@ -95,11 +95,6 @@ func SearchForum(user *User, search *Search, filters ForumSearchFilters, pager * wheres = append(wheres, "forums.explicit = false") } - // Circle membership. - if !user.IsInnerCircle() { - wheres = append(wheres, "forums.inner_circle is not true") - } - // Private forums. if !user.IsAdmin { wheres = append(wheres, "forums.private is not true") diff --git a/pkg/models/notification.go b/pkg/models/notification.go index bad7213..0670af6 100644 --- a/pkg/models/notification.go +++ b/pkg/models/notification.go @@ -45,7 +45,6 @@ const ( NotificationCertApproved NotificationType = "cert_approved" NotificationPrivatePhoto NotificationType = "private_photo" // private photo grants NotificationNewPhoto NotificationType = "new_photo" - NotificationInnerCircle NotificationType = "inner_circle" NotificationCustom NotificationType = "custom" // custom message pushed ) diff --git a/pkg/models/notification_filters.go b/pkg/models/notification_filters.go index ded89b8..a107b8a 100644 --- a/pkg/models/notification_filters.go +++ b/pkg/models/notification_filters.go @@ -12,7 +12,7 @@ type NotificationFilter struct { NewPhotos bool `json:"photos"` AlsoCommented bool `json:"replies"` // also_comment and also_posted PrivatePhoto bool `json:"private"` - Misc bool `json:"misc"` // friendship_approved, cert_approved, cert_rejected, inner_circle, custom + Misc bool `json:"misc"` // friendship_approved, cert_approved, cert_rejected, custom } var defaultNotificationFilter = NotificationFilter{ diff --git a/pkg/models/photo.go b/pkg/models/photo.go index e99189f..2d5958c 100644 --- a/pkg/models/photo.go +++ b/pkg/models/photo.go @@ -33,10 +33,9 @@ type Photo struct { type PhotoVisibility string const ( - PhotoPublic PhotoVisibility = "public" // on profile page and/or public gallery - PhotoFriends PhotoVisibility = "friends" // only friends can see it - PhotoPrivate PhotoVisibility = "private" // private - PhotoInnerCircle PhotoVisibility = "circle" // inner circle + PhotoPublic PhotoVisibility = "public" // on profile page and/or public gallery + PhotoFriends PhotoVisibility = "friends" // only friends can see it + PhotoPrivate PhotoVisibility = "private" // private // Special visibility in case, on User Gallery view, user applies a filter // for friends-only picture but they are not friends with the user. @@ -51,14 +50,6 @@ var ( PhotoPrivate, } - // "All" but also for Inner Circle members. - PhotoVisibilityCircle = []PhotoVisibility{ - PhotoPublic, - PhotoFriends, - PhotoPrivate, - PhotoInnerCircle, - } - // Site Gallery visibility for when your friends show up in the gallery. // Or: "Friends + Gallery" photos can appear to your friends in the Site Gallery. PhotoVisibilityFriends = []string{ @@ -273,11 +264,6 @@ func CountPhotosICanSee(user *User, viewer *User) int64 { PhotoPublic, } - // Is the viewer in the inner circle? - if viewer.IsInnerCircle() { - visibilities = append(visibilities, PhotoInnerCircle) - } - // Is the viewer friends with the target? if AreFriends(user.ID, viewer.ID) { visibilities = append(visibilities, PhotoFriends) @@ -350,7 +336,6 @@ func MapPhotoCounts(users []*User, viewer *User) PhotoCountMap { // User ID filters for the viewer's context. myFriendIDs = FriendIDs(viewer.ID) myPrivateGrantedIDs = PrivateGrantedUserIDs(viewer.ID) - isInnerCircle = viewer.IsInnerCircle() ) // Define "all photos visibilities" @@ -367,10 +352,6 @@ func MapPhotoCounts(users []*User, viewer *User) PhotoCountMap { PhotoPrivate, } ) - if isInnerCircle { - photosPublic = append(photosPublic, PhotoInnerCircle) - photosFriends = append(photosFriends, PhotoInnerCircle) - } // Flatten the userIDs of all passed in users. for _, user := range users { @@ -445,7 +426,7 @@ func CountExplicitPhotos(userID uint64, visibility []PhotoVisibility) (int64, er return count, result.Error } -// CountPublicPhotos returns the number of public photos on a user's page (to control whether the "invite to circle" prompt can appear). +// CountPublicPhotos returns the number of public photos on a user's page. func CountPublicPhotos(userID uint64) int64 { query := DB.Where( "user_id = ? AND visibility = ?", @@ -541,10 +522,6 @@ func PaginateGalleryPhotos(user *User, conf Gallery, pager *Pagination) ([]*Phot PhotoPrivate, } ) - if user.IsInnerCircle() { - photosPublic = append(photosPublic, PhotoInnerCircle) - photosFriends = append(photosFriends, PhotoInnerCircle) - } // Admins see everything on the site (only an admin user can get an admin view). adminView = user.HasAdminScope(config.ScopePhotoModerator) && adminView diff --git a/pkg/models/user.go b/pkg/models/user.go index 4783658..8942747 100644 --- a/pkg/models/user.go +++ b/pkg/models/user.go @@ -28,7 +28,6 @@ type User struct { Birthdate time.Time Certified bool Explicit bool `gorm:"index"` // user has opted-in to see explicit content - InnerCircle bool `gorm:"index"` // user is in the inner circle CreatedAt time.Time `gorm:"index"` UpdatedAt time.Time `gorm:"index"` LastLoginAt time.Time `gorm:"index"` @@ -262,7 +261,6 @@ type UserSearch struct { NearCity *WorldCities Certified bool NotCertified bool - InnerCircle bool ShyAccounts bool IsBanned bool IsDisabled bool @@ -436,11 +434,6 @@ func SearchUsers(user *User, search *UserSearch, pager *Pagination) ([]*User, er wheres = append(wheres, "is_admin = true") } - if search.InnerCircle { - wheres = append(wheres, "inner_circle = ?") - placeholders = append(placeholders, true) - } - if search.ShyAccounts { a, b := WhereClauseShyAccounts() wheres = append(wheres, a) @@ -655,8 +648,6 @@ func (u *User) VisibleAvatarURL(currentUser *User) string { switch visibility { case PhotoPrivate: return "/static/img/shy-private.png" - case PhotoInnerCircle: - return "/static/img/shy-secret.png" case PhotoFriends: return "/static/img/shy-friends.png" } @@ -681,9 +672,6 @@ func (u *User) CanSeeProfilePicture(currentUser *User) (bool, PhotoVisibility) { } else if visibility == PhotoFriends && !u.UserRelationship.IsFriend { // Friends only return false, visibility - } else if visibility == PhotoInnerCircle && currentUser != nil && !currentUser.IsInnerCircle() { - // Inner circle only - return false, visibility } else if u.ProfilePhoto.CroppedFilename != "" { // Happy path return true, visibility diff --git a/pkg/models/user_inner_circle.go b/pkg/models/user_inner_circle.go deleted file mode 100644 index b3f9408..0000000 --- a/pkg/models/user_inner_circle.go +++ /dev/null @@ -1,68 +0,0 @@ -package models - -import ( - "errors" - - "code.nonshy.com/nonshy/website/pkg/config" - "code.nonshy.com/nonshy/website/pkg/log" -) - -// Helper functions relating to the inner circle. - -// IsInnerCircle returns whether the user is in the inner circle (including if the user is an admin, who is always in the inner circle). -func (u *User) IsInnerCircle() bool { - return u.InnerCircle || u.HasAdminScope(config.ScopeIsInnerCircle) -} - -// AddToInnerCircle adds a user to the circle, sending them a notification in the process. -func AddToInnerCircle(u *User) error { - if u.InnerCircle { - return errors.New("already a part of the inner circle") - } - - u.InnerCircle = true - if err := u.Save(); err != nil { - return err - } - - // Send them a notification. - notif := &Notification{ - UserID: u.ID, - AboutUserID: &u.ID, - Type: NotificationInnerCircle, - Link: "/inner-circle", - TableName: "__inner_circle", - TableID: u.ID, - } - if err := CreateNotification(notif); err != nil { - log.Error("AddToInnerCircle: couldn't create notification: %s", err) - } - - return nil -} - -// RemoveFromInnerCircle kicks a user from the inner circle. Any photo they -// had that was marked circle-only is updated to public. -func RemoveFromInnerCircle(u *User) error { - if !u.InnerCircle { - return errors.New("is not a part of the inner circle") - } - - u.InnerCircle = false - if err := u.Save(); err != nil { - return err - } - - // Update their circle-only photos to public. - if err := DB.Model(&Photo{}).Where( - "user_id = ? AND visibility = ?", - u.ID, PhotoInnerCircle, - ).Update("visibility", PhotoPrivate); err != nil { - log.Error("RemoveFromInnerCircle: couldn't update photo visibility: %s", err.Error) - } - - // Revoke any historic notification about the circle. - RemoveNotification("__inner_circle", u.ID) - - return nil -} diff --git a/pkg/models/user_relationship.go b/pkg/models/user_relationship.go index ebaf141..b94fc25 100644 --- a/pkg/models/user_relationship.go +++ b/pkg/models/user_relationship.go @@ -5,10 +5,9 @@ package models // The zero-values should fail safely: in case the UserRelationship isn't populated correctly, // private profile pics show as private by default. type UserRelationship struct { - Computed bool // check whether the SetUserRelationships function has been run - IsFriend bool // if true, a friends-only profile pic can show - IsPrivateGranted bool // if true, a private profile pic can show - IsInnerCirclePeer bool // if true, the current user is in the inner circle so may see circle-only profile picture + Computed bool // check whether the SetUserRelationships function has been run + IsFriend bool // if true, a friends-only profile pic can show + IsPrivateGranted bool // if true, a private profile pic can show } // SetUserRelationships updates a set of User objects to populate their UserRelationships in @@ -18,7 +17,6 @@ func SetUserRelationships(currentUser *User, users []*User) error { var ( friendIDs = FriendIDs(currentUser.ID) privateGrants = PrivateGrantedUserIDs(currentUser.ID) - isInnerCircle = currentUser.IsInnerCircle() ) // Map them for easier lookup. @@ -37,8 +35,6 @@ func SetUserRelationships(currentUser *User, users []*User) error { // Inject the UserRelationships. for _, u := range users { - u.UserRelationship.IsInnerCirclePeer = isInnerCircle - if u.ID == currentUser.ID { // Current user - set both bools to true - you can always see your own profile pic. u.UserRelationship.IsFriend = true diff --git a/pkg/router/router.go b/pkg/router/router.go index b30b299..7a17af9 100644 --- a/pkg/router/router.go +++ b/pkg/router/router.go @@ -78,9 +78,6 @@ func New() http.Handler { mux.Handle("/comments", middleware.LoginRequired(comment.PostComment())) mux.Handle("GET /comments/subscription", middleware.LoginRequired(comment.Subscription())) mux.Handle("GET /admin/unimpersonate", middleware.LoginRequired(admin.Unimpersonate())) - mux.Handle("GET /inner-circle", middleware.LoginRequired(account.InnerCircle())) - mux.Handle("/inner-circle/invite", middleware.LoginRequired(account.InviteCircle())) - mux.Handle("/inner-circle/leave", middleware.LoginRequired(account.LeaveCircle())) mux.Handle("GET /admin/transparency/{username}", middleware.LoginRequired(admin.Transparency())) // Certification Required. Pages that only full (verified) members can access. @@ -105,7 +102,6 @@ func New() http.Handler { mux.Handle("/admin/add-user", middleware.AdminRequired(config.ScopeUserCreate, admin.AddUser())) mux.Handle("/forum/admin", middleware.AdminRequired(config.ScopeForumAdmin, forum.Manage())) mux.Handle("/forum/admin/edit", middleware.AdminRequired(config.ScopeForumAdmin, forum.AddEdit())) - mux.Handle("/inner-circle/remove", middleware.LoginRequired(account.RemoveCircle())) mux.Handle("/admin/photo/mark-explicit", middleware.AdminRequired("", admin.MarkPhotoExplicit())) mux.Handle("GET /admin/changelog", middleware.AdminRequired(config.ScopeChangeLog, admin.ChangeLog())) diff --git a/pkg/templates/template_funcs.go b/pkg/templates/template_funcs.go index a90bd67..af56e89 100644 --- a/pkg/templates/template_funcs.go +++ b/pkg/templates/template_funcs.go @@ -52,11 +52,6 @@ func TemplateFuncs(r *http.Request) template.FuncMap { `s`, ) }, - "PrettyCircle": func() template.HTML { - return template.HTML( - `Inner circle`, - ) - }, "Pluralize": Pluralize[int], "Pluralize64": Pluralize[int64], "PluralizeU64": Pluralize[uint64], diff --git a/web/static/css/theme.css b/web/static/css/theme.css index 0b251c0..85b04b9 100644 --- a/web/static/css/theme.css +++ b/web/static/css/theme.css @@ -94,10 +94,6 @@ img { background-image: linear-gradient(141deg, #b329b1 0, #9948c7 71%, #7156d2 100%); } -.hero.is-inner-circle { - background-image: linear-gradient(141deg, #294eb3 0, #9948c7 71%, #d256d2 100%) -} - /* Mobile: notification badge near the hamburger menu */ .nonshy-mobile-notification { position: absolute; diff --git a/web/templates/about.html b/web/templates/about.html index 74185c6..f801dc2 100644 --- a/web/templates/about.html +++ b/web/templates/about.html @@ -194,10 +194,6 @@ your naked journey.

-

- The most {{PrettyTitle}} of our members may be rewarded with access to exclusive features. -

-

Check out the full Features List for more details.

diff --git a/web/templates/account/dashboard.html b/web/templates/account/dashboard.html index 0a2f3e0..af9de19 100644 --- a/web/templates/account/dashboard.html +++ b/web/templates/account/dashboard.html @@ -218,14 +218,6 @@ Edit Profile & Settings - {{if .CurrentUser.IsInnerCircle}} -
  • - - - {{PrettyCircle}} - -
  • - {{end}}
  • @@ -574,8 +566,6 @@ {{if and $Body.Photo (eq $Body.Photo.Visibility "private")}} - {{else if and $Body.Photo (eq $Body.Photo.Visibility "circle")}} - {{else}} {{end}} @@ -604,15 +594,6 @@ Your certification photo was rejected! - {{else if eq .Type "inner_circle"}} - - - You have been added to the {{PrettyCircle}} of nonshy. - - -
    - Click to learn more about the inner circle. -
    {{else}} {{.AboutUser.Username}} {{.Type}} {{.TableName}} {{.TableID}} {{end}} diff --git a/web/templates/account/friends.html b/web/templates/account/friends.html index 629020d..1681627 100644 --- a/web/templates/account/friends.html +++ b/web/templates/account/friends.html @@ -116,9 +116,6 @@ {{else}} {{.NameOrUsername}} {{end}} - {{if and $Root.CurrentUser.IsInnerCircle .InnerCircle}} - - {{end}} {{if eq .Visibility "private"}} diff --git a/web/templates/account/inner_circle.html b/web/templates/account/inner_circle.html deleted file mode 100644 index cd1696d..0000000 --- a/web/templates/account/inner_circle.html +++ /dev/null @@ -1,220 +0,0 @@ -{{define "title"}}The inner circle{{end}} -{{define "content"}} -
    -
    -
    -
    -

    - - The inner circle -

    -
    -
    -
    -
    - -
    - -
    -
    - -
    - - -
    -

    - Some quick links to {{PrettyCircle}}-only views mentioned - in the description on this page: -

    - - -
    -
    -
    - -
    -

    - Congratulations! You have been added to the {{PrettyCircle}} because you - exemplify what it truly means to be a {{PrettyTitle}} nudist. -

    - -

    What is the inner circle?

    - -

    - The inner circle is for {{PrettyTitle}} members who actually share a lot of nude pictures, - with face, of themselves on their profile page. It is "the party inside the party" - designed only for members who truly embrace the spirit of the {{PrettyTitle}} website by boldly - sharing nude pics with face for other nonshy nudists to see. -

    - -

    - As a member of the inner circle, you can see who else on the website is a part of the circle. Look - for the Inner circle icon on profile pages, the - member directory, forums or the chat room. You may find that some of your {{PrettyTitle}} friends - were already in the circle! People who are not in the circle won't see these indicators - anywhere on the website. -

    - -

    What can I do for being in the inner circle?

    - -

    - As a part of the inner circle, you have access to the following new features: -

    - -
      -
    • - When - Uploading a photo you - have a new Visibility option for "{{PrettyCircle}} " - so that only members of the inner circle can see those pictures. -
    • -
    • - On the - Site Gallery - you can filter for Inner Circle-only photos shared - by other members of the circle. -
    • -
    • - On the - Member Directory - you can see who else is in the inner circle. -
    • -
    • - On the - Forums - you can access exclusive inner circle-only boards. -
    • -
    • - On the - Chat Room you have access - to the exclusive Circle Chat channel, and you can see who else in the chat room is a part of - the inner circle. People outside the circle can't see who the inner circle members are! -
    • -
    • - On your profile page you get an "Inner circle" badge near your - Certified status. This badge is only visible to members of the inner circle. -
    • -
    • - You may invite other members to join the inner circle. -
    • -
    - -

    How does one qualify to be part of the inner circle?

    - -

    - The minimum qualifications for somebody to be in the inner circle include: -

    - -

    - On public visibility, they have at least 5 (five) photos - that show their face and nude body together. -

    - -

    - If you see an inner circle member who had dropped below that threshold later (e.g., they moved - all of their pictures to private or they deleted them all from their page), you may - request removal from the circle when viewing their photo gallery page. Help - us keep the integrity of the inner circle by requesting removals when you see somebody who - should no longer qualify to be in the circle. Removal requests are anonymous! -

    - -

    How do I invite others to join the inner circle?

    - -

    - When you are viewing a member's photo gallery page, look for the prompt at the top of the - page. -

    - -

    - If a member posts several (e.g. {{.InnerCircleMinimumPublicPhotos}}+) nude pics including face you should invite them to join - the inner circle. All members of the circle are allowed to invite new members to join. We trust your - judgment: please only invite like-minded nudists who actually share nudes with face - to join the inner circle. -

    - -

    - Notice: the prompt to invite them to the circle will not be visible if they do not have - at least {{.InnerCircleMinimumPublicPhotos}} public photos on their page at all. - Those public photos aren't necessarily nudes, but hiding the prompt unless they have {{.InnerCircleMinimumPublicPhotos}} - photos can help reduce the risk of inviting somebody on accident. -

    - -

    Please keep the existence of the inner circle a secret

    - -

    - The inner circle is not publicly advertised on the site. This is to help ensure that "bad actors" won't - try and game the system (e.g., by begging somebody to invite them into the circle, or uploading a bare - minimum of nude pics for somebody to invite them only for them to delete their nudes and try and stay - in the inner circle). Plus, it adds an air of exclusivity to keep the existence of the circle on the - down low. -

    - -

    Still continue to share at least some nudes on "public"

    - -

    - With the new Photo visibility option for "inner circle only" you may tag your best nudes for only members - of the inner circle to see. However, you should still continue to share at least some photos on - "Public" as you were doing previously. This is for a couple of reasons: -

    - -
      -
    • - Members who are not in the circle won't see your circle-only photos. If for example you - placed all of your nudes on circle-only you would appear to look the same as someone who - uploaded no nudes at all. -
    • -
    • - The "Shy Account" system of the main website still applies: if you have - not one public photo on your page you may be marked as a Shy Account and be limited from some site - features such as the Chat Room. -
    • -
    - -

    Leave the inner circle

    - -

    - If you would like to opt-out and leave the inner circle, you may do so by clicking - here. -

    -
    -
    - -
    -{{end}} diff --git a/web/templates/account/invite_circle.html b/web/templates/account/invite_circle.html deleted file mode 100644 index 1a555ce..0000000 --- a/web/templates/account/invite_circle.html +++ /dev/null @@ -1,110 +0,0 @@ -{{define "title"}}Invite to the inner circle{{end}} -{{define "content"}} -
    -
    -
    -
    -

    - - Invite to the inner circle -

    -
    -
    -
    - -
    -
    -
    - -
    - -
    - -
    -
    - {{template "avatar-64x64" .User}} -
    -
    -

    {{.User.NameOrUsername}}

    -

    - - {{.User.Username}} -

    -
    -
    - -
    -

    - Do you want to invite {{.User.Username}} to join the - {{PrettyCircle}}? Please review the following notes: -

    - -
      -
    • - The inner circle is designed for {{PrettyTitle}} members who actually post - several nude photos with face on their profile page. - If {{.User.Username}} only has clothed selfies on their page, or keeps - their face hidden or cropped out of their nudes, please do not - invite them to join the inner circle. -
    • -
    • - We especially want people who post such pics on public visibility. - If {{.User.Username}} has several public nude pics with face (e.g. - at least 5 or so pictures), invite them into the circle! -
    • -
    • - All members of the inner circle are allowed to invite others to join the - circle. We trust your judgment -- help ensure that the inner circle is only - made up of truly non-shy nudists who show their whole body on their profile - page. -
    • -
    - -

    - Note: while we use the word "invite" they will actually be added to the inner circle - immediately and receive a notification that they had been added. They won't know that - it was you who invited them to join the circle. -

    - -

    - To proceed, please double check that they have 5 Public photos - that include their face and nude body. -

    -
    - - - -
    -
    - -
    -
    -
    - -
    - - -{{end}} \ No newline at end of file diff --git a/web/templates/account/leave_circle.html b/web/templates/account/leave_circle.html deleted file mode 100644 index a32c751..0000000 --- a/web/templates/account/leave_circle.html +++ /dev/null @@ -1,87 +0,0 @@ -{{define "title"}}Leave the Inner Circle{{end}} -{{define "content"}} -
    -
    -
    -
    -

    - - Leave the Inner Circle -

    -
    -
    -
    - -
    -
    -
    -
    - -
    -
    - {{InputCSRF}} - - -

    - Are you sure that you want to leave the {{PrettyCircle}}? -

    - -

    - This action can not be un-done easily; after leaving the inner circle, the only - way back in is for somebody in the circle to invite you again. -

    - -

    - In case you do not want to be invited into the circle again, - you can check the box below. -

    - - - -
    - - -
    -
    -
    -
    -
    -
    -
    - -
    -{{end}} -{{define "scripts"}} - -{{end}} \ No newline at end of file diff --git a/web/templates/account/profile.html b/web/templates/account/profile.html index a21f967..f07bd74 100644 --- a/web/templates/account/profile.html +++ b/web/templates/account/profile.html @@ -120,17 +120,6 @@ {{end}} - {{if and .CurrentUser.IsInnerCircle .User.IsInnerCircle}} -
    -
    - - - - {{PrettyCircle}} -
    -
    - {{end}} - {{if .User.IsAdmin}}
    diff --git a/web/templates/account/remove_circle.html b/web/templates/account/remove_circle.html deleted file mode 100644 index 5f1aeda..0000000 --- a/web/templates/account/remove_circle.html +++ /dev/null @@ -1,116 +0,0 @@ -{{define "title"}}Remove from the inner circle{{end}} -{{define "content"}} -
    -
    -
    -
    -

    - - Remove from the inner circle -

    -
    -
    -
    - -
    -
    -
    - -
    -
    -

    - - Remove from the inner circle -

    -
    -
    - -
    -
    - {{template "avatar-64x64" .User}} -
    -
    -

    {{.User.NameOrUsername}}

    -

    - - {{.User.Username}} -

    -
    -
    - -
    - {{InputCSRF}} - - - {{if .CurrentUser.HasAdminScope "social.moderator.inner-circle"}} -
    -

    - Do you want to remove {{.User.Username}} from - the {{PrettyCircle}}? Doing so will: -

    - -
      -
    • - Unset their inner circle flag, removing them from all inner circle features. -
    • -
    • - Set any photo they had for "inner circle only" to be "public" instead. -
    • -
    • - Clean up any notification they once received about being invited to the inner circle. -
    • -
    -
    - {{else}} -
    -

    - Do you want to request removal of {{.User.Username}} - from the {{PrettyCircle}}? -

    -

    - If {{.User.Username}} should no longer qualify to be a - part of the inner circle, you may flag them to be removed from the circle. For example: to - be invited into the circle someone should need to have at least 5 (five) pictures - that are on public visibility and which show their face and nude body - together. But if they have taken down their pictures and should no longer qualify to remain in - the {{PrettyCircle}}, you may request them to be removed and an admin will check them out. -

    -

    - Note: removal requests are completely anonymous: we trust your judgment when - inviting others to join the circle so we also trust you to help maintain the integrity of the - circle when flagging people for removal. -

    -
    - {{end}} - -
    - - -
    -
    - -
    -
    - -
    -
    -
    - -
    - - -{{end}} diff --git a/web/templates/account/search.html b/web/templates/account/search.html index 6724b77..0f10898 100644 --- a/web/templates/account/search.html +++ b/web/templates/account/search.html @@ -142,9 +142,6 @@ - {{if .CurrentUser.IsInnerCircle}} - - {{end}} {{if .CurrentUser.HasAdminScope "admin.user.ban"}} @@ -377,9 +374,6 @@ {{else}} {{.NameOrUsername}} {{end}} - {{if and $Root.CurrentUser.IsInnerCircle .InnerCircle}} - - {{end}} {{if eq .Visibility "private"}} diff --git a/web/templates/base.html b/web/templates/base.html index e4c0be9..52d1167 100644 --- a/web/templates/base.html +++ b/web/templates/base.html @@ -201,12 +201,6 @@ My User Notes - {{if .CurrentUser.IsInnerCircle}} - - - Inner circle - - {{end}} Settings diff --git a/web/templates/faq.html b/web/templates/faq.html index e91fddc..098e41b 100644 --- a/web/templates/faq.html +++ b/web/templates/faq.html @@ -419,22 +419,6 @@ granted access to see your private photos.
  • - {{if and .LoggedIn .CurrentUser.IsInnerCircle}} -
  • - {{PrettyCircle}} - : - your profile pic displays as a gradient - - placeholder image for members outside the inner circle. - -
  • - {{end}}

    diff --git a/web/templates/forum/add_edit.html b/web/templates/forum/add_edit.html index 3b0f4d7..a78243f 100644 --- a/web/templates/forum/add_edit.html +++ b/web/templates/forum/add_edit.html @@ -128,19 +128,6 @@

    {{end}} - {{if .CurrentUser.IsAdmin}} - -

    - This forum is only available to inner circle members. -

    - {{end}} - {{if .CurrentUser.IsAdmin}}