Chat Moderation Rules + Shy Accounts on Chat
* Add chat moderation rules to the website, so admins can apply selective rules to problematic users. Available rules are: * redcam: user's camera is always NSFW. * nobroadcast: user can not broadcast their camera. * novideo: user can not broadcast OR watch any video. * noimage: user can not share OR see any shared image on chat. * The page to manage a user's active rules is available on their admin card of their profile page. When the user has rules active, a yellow counter is shown by the link to manage their rules. * Only chat moderator admins have access to the page or can see the yellow counter to know whether rules are active. * "Shy Accounts" are now permitted on the chat room! With some moderation rules automatically applied to them: novideo,noimage. * Update the Shy Account FAQ and messaging on the chat landing page. * Update the auto-kick from chat behavior regarding shy accounts: * They are kicked from chat only when an update to their profile settings will transition then FROM a non-shy into a shy account. * For example: when saving their profile settings (going private) or when editing or deleting a photo (if they will have no more public photos left)
This commit is contained in:
parent
ae84ddf449
commit
066765d2dc
|
@ -37,9 +37,10 @@ func MaybeDisconnectUser(user *models.User) (bool, error) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
If: user.IsShy(),
|
If: user.IsShy(),
|
||||||
Message: because + "you had updated your nonshy profile to become too private.<br><br>" +
|
Message: because + "you had updated your nonshy profile to become too private, and now are considered to have a 'Shy Account.'<br><br>" +
|
||||||
"You may join the chat room after you have made your profile and (at least some) pictures " +
|
"You may <strong>refresh</strong> the page to log back into chat as a Shy Account, where your ability to use webcams and share photos " +
|
||||||
"viewable on 'public' so that you won't appear to be a blank, faceless profile to others on the chat room.<br><br>" +
|
"will be restricted. To regain full access to the chat room, please edit your profile settings to make sure that at least one 'public' " +
|
||||||
|
"photo is viewable to other members of the website.<br><br>" +
|
||||||
"Please see the <a href=\"https://www.nonshy.com/faq#shy-faqs\">Shy Account FAQ</a> for more information.",
|
"Please see the <a href=\"https://www.nonshy.com/faq#shy-faqs\">Shy Account FAQ</a> for more information.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -79,6 +79,7 @@ var (
|
||||||
"dm_privacy",
|
"dm_privacy",
|
||||||
"blur_explicit",
|
"blur_explicit",
|
||||||
"site_gallery_default", // default view on site gallery (friends-only or all certified?)
|
"site_gallery_default", // default view on site gallery (friends-only or all certified?)
|
||||||
|
"chat_moderation_rules",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Choices for the Contact Us subject
|
// Choices for the Contact Us subject
|
||||||
|
@ -119,6 +120,30 @@ var (
|
||||||
regexp.MustCompile(`\b(telegram|whats\s*app|signal|kik|session)\b`),
|
regexp.MustCompile(`\b(telegram|whats\s*app|signal|kik|session)\b`),
|
||||||
regexp.MustCompile(`https?://(t.me|join.skype.com|zoom.us|whereby.com|meet.jit.si|wa.me)`),
|
regexp.MustCompile(`https?://(t.me|join.skype.com|zoom.us|whereby.com|meet.jit.si|wa.me)`),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Chat Moderation Rules.
|
||||||
|
ChatModerationRules = []ChecklistOption{
|
||||||
|
{
|
||||||
|
Value: "redcam",
|
||||||
|
Label: "Red camera",
|
||||||
|
Help: "The user's camera is forced to 'explicit' when they are broadcasting.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Value: "nobroadcast",
|
||||||
|
Label: "No broadcast",
|
||||||
|
Help: "The user can not broadcast their webcam, but may still watch other peoples' webcams.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Value: "novideo",
|
||||||
|
Label: "No webcam privileges",
|
||||||
|
Help: "The user can not broadcast or watch any webcam. Note: this option supercedes all other video-related rules.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Value: "noimage",
|
||||||
|
Label: "No image sharing privileges",
|
||||||
|
Help: "The user can not share or see any image shared on chat.",
|
||||||
|
},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContactUs choices for the subject drop-down.
|
// ContactUs choices for the subject drop-down.
|
||||||
|
@ -133,6 +158,13 @@ type Option struct {
|
||||||
Label string
|
Label string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChecklistOption for checkbox-lists.
|
||||||
|
type ChecklistOption struct {
|
||||||
|
Value string
|
||||||
|
Label string
|
||||||
|
Help string
|
||||||
|
}
|
||||||
|
|
||||||
// NotificationOptout field values (stored in user ProfileField table)
|
// NotificationOptout field values (stored in user ProfileField table)
|
||||||
const (
|
const (
|
||||||
NotificationOptOutFriendPhotos = "notif_optout_friends_photos"
|
NotificationOptOutFriendPhotos = "notif_optout_friends_photos"
|
||||||
|
|
|
@ -3,7 +3,9 @@ package account
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.nonshy.com/nonshy/website/pkg/config"
|
||||||
"code.nonshy.com/nonshy/website/pkg/log"
|
"code.nonshy.com/nonshy/website/pkg/log"
|
||||||
"code.nonshy.com/nonshy/website/pkg/middleware"
|
"code.nonshy.com/nonshy/website/pkg/middleware"
|
||||||
"code.nonshy.com/nonshy/website/pkg/models"
|
"code.nonshy.com/nonshy/website/pkg/models"
|
||||||
|
@ -101,6 +103,14 @@ func Profile() http.HandlerFunc {
|
||||||
log.Error("WhoLikes(user %d): %s", user.ID, err)
|
log.Error("WhoLikes(user %d): %s", user.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Chat Moderation Rule: count of rules applied to the user, for admin view.
|
||||||
|
var chatModerationRules int
|
||||||
|
if currentUser.HasAdminScope(config.ScopeChatModerator) {
|
||||||
|
if rules := user.GetProfileField("chat_moderation_rules"); len(rules) > 0 {
|
||||||
|
chatModerationRules = len(strings.Split(rules, ","))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vars := map[string]interface{}{
|
vars := map[string]interface{}{
|
||||||
"User": user,
|
"User": user,
|
||||||
"LikeMap": likeMap,
|
"LikeMap": likeMap,
|
||||||
|
@ -116,6 +126,9 @@ func Profile() http.HandlerFunc {
|
||||||
"LikeRemainder": likeRemainder,
|
"LikeRemainder": likeRemainder,
|
||||||
"LikeTableName": "users",
|
"LikeTableName": "users",
|
||||||
"LikeTableID": user.ID,
|
"LikeTableID": user.ID,
|
||||||
|
|
||||||
|
// Admin numbers.
|
||||||
|
"NumChatModerationRules": chatModerationRules,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tmpl.Execute(w, r, vars); err != nil {
|
if err := tmpl.Execute(w, r, vars); err != nil {
|
||||||
|
|
|
@ -62,6 +62,10 @@ func Settings() http.HandlerFunc {
|
||||||
|
|
||||||
// Are we POSTing?
|
// Are we POSTing?
|
||||||
if r.Method == http.MethodPost {
|
if r.Method == http.MethodPost {
|
||||||
|
|
||||||
|
// Will they BECOME a Shy Account with this change?
|
||||||
|
var wasShy = user.IsShy()
|
||||||
|
|
||||||
intent := r.PostFormValue("intent")
|
intent := r.PostFormValue("intent")
|
||||||
switch intent {
|
switch intent {
|
||||||
case "profile":
|
case "profile":
|
||||||
|
@ -472,9 +476,11 @@ func Settings() http.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maybe kick them from the chat room if they had become a Shy Account.
|
// Maybe kick them from the chat room if they had become a Shy Account.
|
||||||
|
if !wasShy && user.IsShy() {
|
||||||
if _, err := chat.MaybeDisconnectUser(user); err != nil {
|
if _, err := chat.MaybeDisconnectUser(user); err != nil {
|
||||||
log.Error("chat.MaybeDisconnectUser(%s#%d): %s", user.Username, user.ID, err)
|
log.Error("chat.MaybeDisconnectUser(%s#%d): %s", user.Username, user.ID, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
templates.Redirect(w, r.URL.Path+hashtag+".")
|
templates.Redirect(w, r.URL.Path+hashtag+".")
|
||||||
return
|
return
|
||||||
|
|
|
@ -128,6 +128,48 @@ func UserActions() http.HandlerFunc {
|
||||||
count, total := models.CountBlockedAdminUsers(user)
|
count, total := models.CountBlockedAdminUsers(user)
|
||||||
vars["AdminBlockCount"] = count
|
vars["AdminBlockCount"] = count
|
||||||
vars["AdminBlockTotal"] = total
|
vars["AdminBlockTotal"] = total
|
||||||
|
case "chat.rules":
|
||||||
|
// Chat Moderation Rules.
|
||||||
|
if !currentUser.HasAdminScope(config.ScopeChatModerator) {
|
||||||
|
session.FlashError(w, r, "Missing admin scope: %s", config.ScopeChatModerator)
|
||||||
|
templates.Redirect(w, "/admin")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Method == http.MethodPost {
|
||||||
|
// Rules list for the change log.
|
||||||
|
var newRules = "(none)"
|
||||||
|
if rule, ok := r.PostForm["rules"]; ok {
|
||||||
|
newRules = strings.Join(rule, ",")
|
||||||
|
user.SetProfileField("chat_moderation_rules", newRules)
|
||||||
|
} else {
|
||||||
|
user.DeleteProfileField("chat_moderation_rules")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := user.Save(); err != nil {
|
||||||
|
session.FlashError(w, r, "Error saving the user's chat rules: %s", err)
|
||||||
|
} else {
|
||||||
|
session.Flash(w, r, "Chat moderation rules have been updated!")
|
||||||
|
}
|
||||||
|
templates.Redirect(w, "/u/"+user.Username)
|
||||||
|
|
||||||
|
// Log the new rules to the changelog.
|
||||||
|
models.LogEvent(
|
||||||
|
user,
|
||||||
|
currentUser,
|
||||||
|
"updated",
|
||||||
|
"chat.rules",
|
||||||
|
user.ID,
|
||||||
|
fmt.Sprintf(
|
||||||
|
"An admin has updated the chat moderation rules for this user.\n\n"+
|
||||||
|
"The update rules are: %s",
|
||||||
|
newRules,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars["ChatModerationRules"] = config.ChatModerationRules
|
||||||
case "essays":
|
case "essays":
|
||||||
// Edit their profile essays easily.
|
// Edit their profile essays easily.
|
||||||
if !currentUser.HasAdminScope(config.ScopePhotoModerator) {
|
if !currentUser.HasAdminScope(config.ScopePhotoModerator) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ type Claims struct {
|
||||||
Nickname string `json:"nick,omitempty"`
|
Nickname string `json:"nick,omitempty"`
|
||||||
Emoji string `json:"emoji,omitempty"`
|
Emoji string `json:"emoji,omitempty"`
|
||||||
Gender string `json:"gender,omitempty"`
|
Gender string `json:"gender,omitempty"`
|
||||||
|
Rules []string `json:"rules,omitempty"`
|
||||||
|
|
||||||
// Standard claims. Notes:
|
// Standard claims. Notes:
|
||||||
// subject = username
|
// subject = username
|
||||||
|
@ -76,16 +77,6 @@ func Landing() http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are shy, block chat for now.
|
|
||||||
if isShy {
|
|
||||||
session.FlashError(w, r,
|
|
||||||
"You have a Shy Account and are not allowed in the chat room at this time where our non-shy members may "+
|
|
||||||
"be on camera.",
|
|
||||||
)
|
|
||||||
templates.Redirect(w, "/chat")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get our Chat JWT secret.
|
// Get our Chat JWT secret.
|
||||||
var (
|
var (
|
||||||
secret = []byte(config.Current.BareRTC.JWTSecret)
|
secret = []byte(config.Current.BareRTC.JWTSecret)
|
||||||
|
@ -120,6 +111,16 @@ func Landing() http.HandlerFunc {
|
||||||
emoji = "🍰 It's my birthday!"
|
emoji = "🍰 It's my birthday!"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply chat moderation rules.
|
||||||
|
var rules = []string{}
|
||||||
|
if isShy {
|
||||||
|
// Shy account: no camera privileges.
|
||||||
|
rules = []string{"novideo", "noimage"}
|
||||||
|
} else if v := currentUser.GetProfileField("chat_moderation_rules"); len(v) > 0 {
|
||||||
|
// Specific mod rules applied to the current user.
|
||||||
|
rules = strings.Split(v, ",")
|
||||||
|
}
|
||||||
|
|
||||||
// Create the JWT claims.
|
// Create the JWT claims.
|
||||||
claims := Claims{
|
claims := Claims{
|
||||||
IsAdmin: currentUser.HasAdminScope(config.ScopeChatModerator),
|
IsAdmin: currentUser.HasAdminScope(config.ScopeChatModerator),
|
||||||
|
@ -128,6 +129,8 @@ func Landing() http.HandlerFunc {
|
||||||
Nickname: currentUser.NameOrUsername(),
|
Nickname: currentUser.NameOrUsername(),
|
||||||
Emoji: emoji,
|
Emoji: emoji,
|
||||||
Gender: Gender(currentUser),
|
Gender: Gender(currentUser),
|
||||||
|
VIP: isShy, // "shy accounts" use the "VIP" status for special icon in chat
|
||||||
|
Rules: rules,
|
||||||
RegisteredClaims: jwt.RegisteredClaims{
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(5 * time.Minute)),
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(5 * time.Minute)),
|
||||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||||
|
|
|
@ -71,6 +71,9 @@ func Edit() http.HandlerFunc {
|
||||||
|
|
||||||
// Are we saving the changes?
|
// Are we saving the changes?
|
||||||
if r.Method == http.MethodPost {
|
if r.Method == http.MethodPost {
|
||||||
|
// Record if this change is going to make them a Shy Account.
|
||||||
|
var wasShy = currentUser.IsShy()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
caption = strings.TrimSpace(r.FormValue("caption"))
|
caption = strings.TrimSpace(r.FormValue("caption"))
|
||||||
altText = strings.TrimSpace(r.FormValue("alt_text"))
|
altText = strings.TrimSpace(r.FormValue("alt_text"))
|
||||||
|
@ -158,9 +161,12 @@ func Edit() http.HandlerFunc {
|
||||||
models.LogUpdated(currentUser, requestUser, "photos", photo.ID, "Updated the photo's settings.", diffs)
|
models.LogUpdated(currentUser, requestUser, "photos", photo.ID, "Updated the photo's settings.", diffs)
|
||||||
|
|
||||||
// Maybe kick them from the chat if this photo save makes them a Shy Account.
|
// Maybe kick them from the chat if this photo save makes them a Shy Account.
|
||||||
|
currentUser.FlushCaches()
|
||||||
|
if !wasShy && currentUser.IsShy() {
|
||||||
if _, err := chat.MaybeDisconnectUser(currentUser); err != nil {
|
if _, err := chat.MaybeDisconnectUser(currentUser); err != nil {
|
||||||
log.Error("chat.MaybeDisconnectUser(%s#%d): %s", currentUser.Username, currentUser.ID, err)
|
log.Error("chat.MaybeDisconnectUser(%s#%d): %s", currentUser.Username, currentUser.ID, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If this picture has moved to Private, revoke any notification we gave about it before.
|
// If this picture has moved to Private, revoke any notification we gave about it before.
|
||||||
if goingPrivate {
|
if goingPrivate {
|
||||||
|
@ -242,6 +248,9 @@ func Delete() http.HandlerFunc {
|
||||||
|
|
||||||
// Confirm deletion?
|
// Confirm deletion?
|
||||||
if r.Method == http.MethodPost {
|
if r.Method == http.MethodPost {
|
||||||
|
// Record if this change is going to make them a Shy Account.
|
||||||
|
var wasShy = currentUser.IsShy()
|
||||||
|
|
||||||
confirm := r.PostFormValue("confirm") == "true"
|
confirm := r.PostFormValue("confirm") == "true"
|
||||||
if !confirm {
|
if !confirm {
|
||||||
session.FlashError(w, r, "Confirm you want to delete this photo.")
|
session.FlashError(w, r, "Confirm you want to delete this photo.")
|
||||||
|
@ -286,9 +295,12 @@ func Delete() http.HandlerFunc {
|
||||||
session.Flash(w, r, "Photo deleted!")
|
session.Flash(w, r, "Photo deleted!")
|
||||||
|
|
||||||
// Maybe kick them from chat if this deletion makes them into a Shy Account.
|
// Maybe kick them from chat if this deletion makes them into a Shy Account.
|
||||||
|
currentUser.FlushCaches()
|
||||||
|
if !wasShy && currentUser.IsShy() {
|
||||||
if _, err := chat.MaybeDisconnectUser(currentUser); err != nil {
|
if _, err := chat.MaybeDisconnectUser(currentUser); err != nil {
|
||||||
log.Error("chat.MaybeDisconnectUser(%s#%d): %s", currentUser.Username, currentUser.ID, err)
|
log.Error("chat.MaybeDisconnectUser(%s#%d): %s", currentUser.Username, currentUser.ID, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Return the user to their gallery.
|
// Return the user to their gallery.
|
||||||
templates.Redirect(w, "/u/"+currentUser.Username+"/photos")
|
templates.Redirect(w, "/u/"+currentUser.Username+"/photos")
|
||||||
|
|
|
@ -472,6 +472,13 @@ func (u *User) DistinctPhotoTypes() (result map[PhotoVisibility]struct{}) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FlushCaches clears any cached attributes (such as distinct photo types) for the user.
|
||||||
|
func (u *User) FlushCaches() {
|
||||||
|
u.cachePhotoTypes = nil
|
||||||
|
u.cacheBlockedUserIDs = nil
|
||||||
|
u.cachePhotoIDs = nil
|
||||||
|
}
|
||||||
|
|
||||||
// Gallery config for the main Gallery paginator.
|
// Gallery config for the main Gallery paginator.
|
||||||
type Gallery struct {
|
type Gallery struct {
|
||||||
Explicit string // Explicit filter
|
Explicit string // Explicit filter
|
||||||
|
|
|
@ -807,6 +807,15 @@ func (u *User) SetProfileField(name, value string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteProfileField removes a stored profile field.
|
||||||
|
func (u *User) DeleteProfileField(name string) error {
|
||||||
|
res := DB.Raw(
|
||||||
|
"DELETE FROM profile_fields WHERE user_id=? AND name=?",
|
||||||
|
u.ID, name,
|
||||||
|
)
|
||||||
|
return res.Error
|
||||||
|
}
|
||||||
|
|
||||||
// GetProfileField returns the value of a profile field or blank string.
|
// GetProfileField returns the value of a profile field or blank string.
|
||||||
func (u *User) GetProfileField(name string) string {
|
func (u *User) GetProfileField(name string) string {
|
||||||
for _, field := range u.ProfileField {
|
for _, field := range u.ProfileField {
|
||||||
|
|
|
@ -492,6 +492,17 @@
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<p class="menu-label">Admin Actions</p>
|
<p class="menu-label">Admin Actions</p>
|
||||||
|
<li>
|
||||||
|
<a href="/admin/user-action?intent=chat.rules&user_id={{.User.ID}}">
|
||||||
|
<span class="icon"><i class="fa fa-gavel"></i></span>
|
||||||
|
<span>
|
||||||
|
Chat Moderation Rules
|
||||||
|
{{if .NumChatModerationRules}}
|
||||||
|
<span class="tag is-warning ml-2">{{.NumChatModerationRules}}</span>
|
||||||
|
{{end}}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/admin/user-action?intent=essays&user_id={{.User.ID}}">
|
<a href="/admin/user-action?intent=essays&user_id={{.User.ID}}">
|
||||||
<span class="icon"><i class="fa fa-pencil"></i></span>
|
<span class="icon"><i class="fa fa-pencil"></i></span>
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{{$Root := .}}
|
||||||
|
|
||||||
<div class="block p-4">
|
<div class="block p-4">
|
||||||
<div class="columns is-centered">
|
<div class="columns is-centered">
|
||||||
<div class="column is-half">
|
<div class="column is-half">
|
||||||
|
@ -22,6 +24,9 @@
|
||||||
{{if eq .Intent "impersonate"}}
|
{{if eq .Intent "impersonate"}}
|
||||||
<i class="mr-2 fa fa-ghost"></i>
|
<i class="mr-2 fa fa-ghost"></i>
|
||||||
Impersonate User
|
Impersonate User
|
||||||
|
{{else if eq .Intent "chat.rules"}}
|
||||||
|
<i class="mr-2 fa fa-gavel"></i>
|
||||||
|
Chat Moderation Rules
|
||||||
{{else if eq .Intent "essays"}}
|
{{else if eq .Intent "essays"}}
|
||||||
<i class="mr-2 fa fa-pencil"></i>
|
<i class="mr-2 fa fa-pencil"></i>
|
||||||
Edit Profile Text
|
Edit Profile Text
|
||||||
|
@ -171,6 +176,45 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{else if eq .Intent "chat.rules"}}
|
||||||
|
<div class="block content">
|
||||||
|
<p>
|
||||||
|
You may use this page to add or remove <strong>chat moderation rules</strong> for this user account.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Moderation rules are useful to apply restrictions to certain problematic users who habitually break
|
||||||
|
the site rules. For example: somebody who insists on keeping their camera "blue" (non-explicit) while
|
||||||
|
always jerking off and resisting the admin request that their camera should be marked "red" can have that
|
||||||
|
choice taken away from them, and have their camera be forced red at all times when they are broadcasting.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<strong>Note:</strong> <a href="/faq#shy-faqs">"Shy Accounts"</a> automatically have the <strong>No webcam privileges</strong>
|
||||||
|
and <strong>No image sharing privileges</strong> rules applied when they log onto the chat room.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{range .ChatModerationRules}}
|
||||||
|
<div class="field">
|
||||||
|
<label class="checkbox">
|
||||||
|
<input type="checkbox"
|
||||||
|
name="rules"
|
||||||
|
value="{{.Value}}"
|
||||||
|
{{if $Root.User.ProfileFieldIn "chat_moderation_rules" .Value}}checked{{end}}>
|
||||||
|
{{.Label}}
|
||||||
|
</label>
|
||||||
|
<p class="help">
|
||||||
|
{{.Help}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<div class="field has-text-centered">
|
||||||
|
<button type="submit" class="button is-success">
|
||||||
|
Save Changes
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
{{else if eq .Intent "essays"}}
|
{{else if eq .Intent "essays"}}
|
||||||
<div class="block content">
|
<div class="block content">
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -48,11 +48,27 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if .IsShyUser}}
|
{{if .IsShyUser}}
|
||||||
<div class="notification is-danger is-light">
|
<div class="notification is-warning is-light content">
|
||||||
<i class="fa fa-exclamation-triangle"></i> You have a <strong>Shy Account</strong> and you may not enter
|
<p>
|
||||||
the chat room at this time, where our {{PrettyTitle}} members may be sharing their cameras. You are
|
<i class="fa fa-exclamation-triangle"></i> You have a <strong>Shy Account</strong>, so you will experience
|
||||||
sharing no public photos with the community, so you get limited access to ours.
|
limited functionality on the chat room:
|
||||||
<a href="/faq#shy-faqs">Learn more about how to resolve this issue. <small class="fa fa-external-link"></small></a>
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>You may not broadcast or watch any webcam on chat.</li>
|
||||||
|
<li>You may not share or see pictures shared by other members on chat.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This is because, as a Shy Account, you are not sharing any public photos with the community on your profile
|
||||||
|
page, so to most other members of {{PrettyTitle}} you appear to be a "blank, faceless profile" and people on
|
||||||
|
the chat room generally feel uncomfortable having their webcams be watched by such a Shy Account.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a href="/faq#shy-faqs">Click here to learn more</a> about your Shy Account, including steps on how to
|
||||||
|
resolve this.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
|
|
@ -1131,8 +1131,8 @@
|
||||||
<p>
|
<p>
|
||||||
The chat room is available to all <strong>certified</strong> members who have public photos
|
The chat room is available to all <strong>certified</strong> members who have public photos
|
||||||
on their profile page. <a href="#shy-faqs">Shy Accounts</a> who have private profiles or keep
|
on their profile page. <a href="#shy-faqs">Shy Accounts</a> who have private profiles or keep
|
||||||
all their pictures hidden are not permitted in the chat room at this time - but they may get
|
all their pictures hidden MAY join the chat room, but have certain restrictions applied (such
|
||||||
their own separate room later where they can bother other similarly shy members there.
|
as an inability to broadcast or watch any webcam, or share or see any picture shared on chat).
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -1400,9 +1400,9 @@
|
||||||
your Friend or have shared their private pictures with you.
|
your Friend or have shared their private pictures with you.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
You can not join the <i class="fa fa-message"></i> <strong>Chat Room</strong>. You guys
|
You <strong>can</strong> join the <i class="fa fa-message"></i> <strong>Chat Room</strong>, however
|
||||||
may soon get your own chat room, though. Many of us {{PrettyTitle}} nudists would not
|
some features will be restricted to Shy Accounts: you will not be able to broadcast OR watch any webcam
|
||||||
enjoy our webcams being watched by blank profiles.
|
on chat, nor can you share OR view any photo shared by others on the chat room.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -1413,6 +1413,13 @@
|
||||||
kept with the other blank profiles until you choose to participate.
|
kept with the other blank profiles until you choose to participate.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
On the chat room, many {{PrettyTitle}} members may be sharing their webcams and it is widely
|
||||||
|
regarded as awkward to have a "blank, faceless profile" silently lurking on your camera. So, a
|
||||||
|
Shy Account is allowed on the chat room but can not share or watch webcams, or share or view photos
|
||||||
|
posted by other members on the chat room.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3 id="shy-cando">What <em>can</em> Shy Accounts do?</h3>
|
<h3 id="shy-cando">What <em>can</em> Shy Accounts do?</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -1421,6 +1428,10 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>
|
||||||
|
You can still join the <i class="fa fa-message"></i> <strong>Chat Room</strong> and have text-based
|
||||||
|
conversations with people (with just webcam and image sharing support restricted).
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
You can still participate on the <i class="fa fa-comments"></i> <strong>Forums</strong> and meet new friends
|
You can still participate on the <i class="fa fa-comments"></i> <strong>Forums</strong> and meet new friends
|
||||||
that way - by contributing to discussions, ideally.
|
that way - by contributing to discussions, ideally.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user