Shy Accounts
* Users with private profiles or no public photo at all are considered to be Shy Accounts and are isolated from the non-shy profiles. * Restrictions include: * Site Gallery shows only them + their friends' photos. * User Galleries: must be a friend or had private photos granted to see a user's gallery page. * DMs: can not initiate a DM to a non-shy member (other shy members OK).
This commit is contained in:
parent
c4600ff6ce
commit
7d17dce4d4
|
@ -43,10 +43,21 @@ func Dashboard() http.HandlerFunc {
|
||||||
notifMap := models.MapNotifications(notifs)
|
notifMap := models.MapNotifications(notifs)
|
||||||
models.SetUserRelationshipsInNotifications(currentUser, notifs)
|
models.SetUserRelationshipsInNotifications(currentUser, notifs)
|
||||||
|
|
||||||
|
// Restricted profile warnings.
|
||||||
|
var (
|
||||||
|
isShyUser = currentUser.IsShy()
|
||||||
|
photoTypes = currentUser.DistinctPhotoTypes()
|
||||||
|
_, hasPublic = photoTypes[models.PhotoPublic]
|
||||||
|
)
|
||||||
|
|
||||||
var vars = map[string]interface{}{
|
var vars = map[string]interface{}{
|
||||||
"Notifications": notifs,
|
"Notifications": notifs,
|
||||||
"NotifMap": notifMap,
|
"NotifMap": notifMap,
|
||||||
"Pager": pager,
|
"Pager": pager,
|
||||||
|
|
||||||
|
// Show a warning to 'restricted' profiles who are especially private.
|
||||||
|
"IsShyUser": isShyUser,
|
||||||
|
"HasPublicPhoto": hasPublic,
|
||||||
}
|
}
|
||||||
if err := tmpl.Execute(w, r, vars); err != nil {
|
if err := tmpl.Execute(w, r, vars); err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
|
|
@ -39,8 +39,21 @@ func Landing() http.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Are they logging into the chat room?
|
// Are they logging into the chat room?
|
||||||
var intent = r.FormValue("intent")
|
var (
|
||||||
|
intent = r.FormValue("intent")
|
||||||
|
isShy = currentUser.IsShy()
|
||||||
|
)
|
||||||
if intent == "join" {
|
if intent == "join" {
|
||||||
|
// 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)
|
||||||
|
@ -91,7 +104,8 @@ func Landing() http.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
var vars = map[string]interface{}{
|
var vars = map[string]interface{}{
|
||||||
"ChatAPI": strings.TrimSuffix(config.Current.BareRTC.URL, "/") + "/api/statistics",
|
"ChatAPI": strings.TrimSuffix(config.Current.BareRTC.URL, "/") + "/api/statistics",
|
||||||
|
"IsShyUser": isShy,
|
||||||
}
|
}
|
||||||
if err := tmpl.Execute(w, r, vars); err != nil {
|
if err := tmpl.Execute(w, r, vars); err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
|
|
@ -69,6 +69,18 @@ func Compose() http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On GET request (come from a user profile page):
|
||||||
|
// Do not allow a shy user to initiate DMs with a non-shy one.
|
||||||
|
var (
|
||||||
|
imShy = currentUser.IsShy()
|
||||||
|
isShyFrom = currentUser.IsShyFrom(user) || (imShy && !models.AreFriends(currentUser.ID, user.ID))
|
||||||
|
)
|
||||||
|
if imShy && isShyFrom {
|
||||||
|
session.FlashError(w, r, "You have a Shy Account and can not initiate Direct Messages with a non-shy member.")
|
||||||
|
templates.Redirect(w, "/u/"+user.Username)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var vars = map[string]interface{}{
|
var vars = map[string]interface{}{
|
||||||
"User": user,
|
"User": user,
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,9 @@ func SiteGallery() http.HandlerFunc {
|
||||||
session.FlashError(w, r, "Unexpected error: couldn't get CurrentUser")
|
session.FlashError(w, r, "Unexpected error: couldn't get CurrentUser")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is the current viewer shy?
|
||||||
|
var isShy = currentUser.IsShy()
|
||||||
|
|
||||||
// Get the page of photos.
|
// Get the page of photos.
|
||||||
pager := &models.Pagination{
|
pager := &models.Pagination{
|
||||||
Page: 1,
|
Page: 1,
|
||||||
|
@ -61,7 +64,12 @@ func SiteGallery() http.HandlerFunc {
|
||||||
Sort: sort,
|
Sort: sort,
|
||||||
}
|
}
|
||||||
pager.ParsePage(r)
|
pager.ParsePage(r)
|
||||||
photos, err := models.PaginateGalleryPhotos(currentUser, filterExplicit, filterVisibility, adminView, pager)
|
photos, _ := models.PaginateGalleryPhotos(currentUser, models.Gallery{
|
||||||
|
Explicit: filterExplicit,
|
||||||
|
Visibility: filterVisibility,
|
||||||
|
AdminView: adminView,
|
||||||
|
ShyView: isShy,
|
||||||
|
}, pager)
|
||||||
|
|
||||||
// Bulk load the users associated with these photos.
|
// Bulk load the users associated with these photos.
|
||||||
var userIDs = []uint64{}
|
var userIDs = []uint64{}
|
||||||
|
@ -95,6 +103,9 @@ func SiteGallery() http.HandlerFunc {
|
||||||
"FilterExplicit": filterExplicit,
|
"FilterExplicit": filterExplicit,
|
||||||
"FilterVisibility": filterVisibility,
|
"FilterVisibility": filterVisibility,
|
||||||
"AdminView": adminView,
|
"AdminView": adminView,
|
||||||
|
|
||||||
|
// Is the current user shy?
|
||||||
|
"IsShyUser": isShy,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tmpl.Execute(w, r, vars); err != nil {
|
if err := tmpl.Execute(w, r, vars); err != nil {
|
||||||
|
|
|
@ -43,7 +43,31 @@ func UserPhotos() http.HandlerFunc {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
session.FlashError(w, r, "Unexpected error: couldn't get CurrentUser")
|
session.FlashError(w, r, "Unexpected error: couldn't get CurrentUser")
|
||||||
}
|
}
|
||||||
var isOwnPhotos = currentUser.ID == user.ID
|
var (
|
||||||
|
isOwnPhotos = currentUser.ID == user.ID
|
||||||
|
isShy = currentUser.IsShy()
|
||||||
|
isShyFrom = currentUser.IsShyFrom(user) || (isShy && !models.AreFriends(currentUser.ID, user.ID))
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bail early if we are shy from this user.
|
||||||
|
if isShy && isShyFrom {
|
||||||
|
var vars = map[string]interface{}{
|
||||||
|
"IsOwnPhotos": currentUser.ID == user.ID,
|
||||||
|
"IsShyUser": isShy,
|
||||||
|
"IsShyFrom": isShyFrom,
|
||||||
|
// "IsMyPrivateUnlockedFor": isGranted, // have WE granted THIS USER to see our private pics?
|
||||||
|
// "AreWeGrantedPrivate": isGrantee, // have THEY granted US private photo access.
|
||||||
|
"User": user,
|
||||||
|
"Photos": []*models.Photo{},
|
||||||
|
"PhotoCount": models.CountPhotos(user.ID),
|
||||||
|
"Pager": models.Pagination{},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tmpl.Execute(w, r, vars); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Is either one blocking?
|
// Is either one blocking?
|
||||||
if models.IsBlocking(currentUser.ID, user.ID) && !currentUser.IsAdmin {
|
if models.IsBlocking(currentUser.ID, user.ID) && !currentUser.IsAdmin {
|
||||||
|
@ -107,6 +131,8 @@ func UserPhotos() http.HandlerFunc {
|
||||||
|
|
||||||
var vars = map[string]interface{}{
|
var vars = map[string]interface{}{
|
||||||
"IsOwnPhotos": currentUser.ID == user.ID,
|
"IsOwnPhotos": currentUser.ID == user.ID,
|
||||||
|
"IsShyUser": isShy,
|
||||||
|
"IsShyFrom": isShyFrom,
|
||||||
"IsMyPrivateUnlockedFor": isGranted, // have WE granted THIS USER to see our private pics?
|
"IsMyPrivateUnlockedFor": isGranted, // have WE granted THIS USER to see our private pics?
|
||||||
"AreWeGrantedPrivate": isGrantee, // have THEY granted US private photo access.
|
"AreWeGrantedPrivate": isGrantee, // have THEY granted US private photo access.
|
||||||
"User": user,
|
"User": user,
|
||||||
|
|
|
@ -85,6 +85,9 @@ func (p *Pagination) Iter() []Page {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pagination) Pages() int {
|
func (p *Pagination) Pages() int {
|
||||||
|
if p.PerPage == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
return int(math.Ceil(float64(p.Total) / float64(p.PerPage)))
|
return int(math.Ceil(float64(p.Total) / float64(p.PerPage)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -150,15 +150,57 @@ func CountExplicitPhotos(userID uint64, visibility []PhotoVisibility) (int64, er
|
||||||
return count, result.Error
|
return count, result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DistinctPhotoTypes returns types of photos the user has: a set of public, friends, or private.
|
||||||
|
//
|
||||||
|
// The result is cached on the User the first time it's queried.
|
||||||
|
func (u *User) DistinctPhotoTypes() (result map[PhotoVisibility]struct{}) {
|
||||||
|
if u.cachePhotoTypes != nil {
|
||||||
|
return u.cachePhotoTypes
|
||||||
|
}
|
||||||
|
|
||||||
|
result = map[PhotoVisibility]struct{}{}
|
||||||
|
|
||||||
|
var results = []*Photo{}
|
||||||
|
query := DB.Model(&Photo{}).
|
||||||
|
Select("DISTINCT photos.visibility").
|
||||||
|
Where("user_id = ?", u.ID).
|
||||||
|
Group("photos.visibility").
|
||||||
|
Find(&results)
|
||||||
|
if query.Error != nil {
|
||||||
|
log.Error("User.DistinctPhotoTypes(%s): %s", u.Username, query.Error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, row := range results {
|
||||||
|
log.Warn("DistinctPhotoTypes(%s): got %+v", u.Username, row)
|
||||||
|
result[row.Visibility] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
u.cachePhotoTypes = result
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gallery config for the main Gallery paginator.
|
||||||
|
type Gallery struct {
|
||||||
|
Explicit string // Explicit filter
|
||||||
|
Visibility string // Visibility filter
|
||||||
|
AdminView bool // Show all images
|
||||||
|
ShyView bool // Current user is shy (self/friends only)
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
PaginateGalleryPhotos gets a page of all public user photos for the site gallery.
|
PaginateGalleryPhotos gets a page of all public user photos for the site gallery.
|
||||||
|
|
||||||
Admin view returns ALL photos regardless of Gallery status.
|
Admin view returns ALL photos regardless of Gallery status.
|
||||||
*/
|
*/
|
||||||
func PaginateGalleryPhotos(user *User, filterExplicit, filterVisibility string, adminView bool, pager *Pagination) ([]*Photo, error) {
|
func PaginateGalleryPhotos(user *User, conf Gallery, pager *Pagination) ([]*Photo, error) {
|
||||||
var (
|
var (
|
||||||
p = []*Photo{}
|
filterExplicit = conf.Explicit
|
||||||
query *gorm.DB
|
filterVisibility = conf.Visibility
|
||||||
|
adminView = conf.AdminView
|
||||||
|
isShy = conf.ShyView
|
||||||
|
p = []*Photo{}
|
||||||
|
query *gorm.DB
|
||||||
|
|
||||||
// Get the user ID and their preferences.
|
// Get the user ID and their preferences.
|
||||||
userID = user.ID
|
userID = user.ID
|
||||||
|
@ -177,17 +219,31 @@ func PaginateGalleryPhotos(user *User, filterExplicit, filterVisibility string,
|
||||||
// Include ourself in our friend IDs.
|
// Include ourself in our friend IDs.
|
||||||
friendIDs = append(friendIDs, userID)
|
friendIDs = append(friendIDs, userID)
|
||||||
|
|
||||||
// You can see friends' Friend photos but only public for non-friends.
|
// Whose photos can you see on the Site Gallery?
|
||||||
wheres = append(wheres,
|
if isShy {
|
||||||
"((user_id IN ? AND visibility IN ?) OR "+
|
// Shy users can only see their Friends photos (public or friends visibility)
|
||||||
"(user_id IN ? AND visibility IN ?) OR "+
|
// and any Private photos to whom they were granted access.
|
||||||
"(user_id NOT IN ? AND visibility = ?))",
|
wheres = append(wheres,
|
||||||
)
|
"((user_id IN ? AND visibility IN ?) OR "+
|
||||||
placeholders = append(placeholders,
|
"(user_id IN ? AND visibility IN ?))",
|
||||||
friendIDs, PhotoVisibilityFriends,
|
)
|
||||||
privateUserIDs, PhotoVisibilityAll,
|
placeholders = append(placeholders,
|
||||||
friendIDs, PhotoPublic,
|
friendIDs, PhotoVisibilityFriends,
|
||||||
)
|
privateUserIDs, PhotoVisibilityAll,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// You can see friends' Friend photos but only public for non-friends.
|
||||||
|
wheres = append(wheres,
|
||||||
|
"((user_id IN ? AND visibility IN ?) OR "+
|
||||||
|
"(user_id IN ? AND visibility IN ?) OR "+
|
||||||
|
"(user_id NOT IN ? AND visibility = ?))",
|
||||||
|
)
|
||||||
|
placeholders = append(placeholders,
|
||||||
|
friendIDs, PhotoVisibilityFriends,
|
||||||
|
privateUserIDs, PhotoVisibilityAll,
|
||||||
|
friendIDs, PhotoPublic,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Gallery photos only.
|
// Gallery photos only.
|
||||||
wheres = append(wheres, "gallery = ?")
|
wheres = append(wheres, "gallery = ?")
|
||||||
|
|
|
@ -37,6 +37,9 @@ type User struct {
|
||||||
|
|
||||||
// Current user's relationship to this user -- not stored in DB.
|
// Current user's relationship to this user -- not stored in DB.
|
||||||
UserRelationship UserRelationship `gorm:"-"`
|
UserRelationship UserRelationship `gorm:"-"`
|
||||||
|
|
||||||
|
// Caches
|
||||||
|
cachePhotoTypes map[PhotoVisibility]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserVisibility string
|
type UserVisibility string
|
||||||
|
@ -132,6 +135,49 @@ func FindUser(username string) (*User, error) {
|
||||||
return u, result.Error
|
return u, result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsShy returns whether the user might have an "empty" profile from the perspective of anybody.
|
||||||
|
//
|
||||||
|
// An empty profile means their profile is Private or else ALL of their photos are non-public; so that
|
||||||
|
// somebody viewing their page might see nothing at all from them and consider them a "blank" profile.
|
||||||
|
func (u *User) IsShy() bool {
|
||||||
|
// Non-certified users are considered empty.
|
||||||
|
if !u.Certified {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private profile automatically applies.
|
||||||
|
if u.Visibility == UserVisibilityPrivate {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// If ALL of our photos are non-public, that counts too.
|
||||||
|
var photoTypes = u.DistinctPhotoTypes()
|
||||||
|
if _, ok := photoTypes[PhotoPublic]; !ok {
|
||||||
|
log.Info("IsEmptyProfile: true because visibilities %+v did not include public", photoTypes)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsShyFrom tells whether the user is shy from the perspective of the other user.
|
||||||
|
//
|
||||||
|
// That is, depending on our profile visibility and friendship status.
|
||||||
|
func (u *User) IsShyFrom(other *User) bool {
|
||||||
|
// If we are not a private profile, we're shy from nobody.
|
||||||
|
if u.Visibility != UserVisibilityPrivate {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not shy from our friends.
|
||||||
|
if AreFriends(u.ID, other.ID) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our profile must be private & we are not friended, we are shy.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// UserSearch config.
|
// UserSearch config.
|
||||||
type UserSearch struct {
|
type UserSearch struct {
|
||||||
EmailOrUsername string
|
EmailOrUsername string
|
||||||
|
|
|
@ -68,6 +68,71 @@
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
<!-- "Very Private" Restricted Account warning for certified users -->
|
||||||
|
{{if and .CurrentUser.Certified .IsShyUser}}
|
||||||
|
<div class="card block">
|
||||||
|
<header class="card-header has-background-danger">
|
||||||
|
<p class="card-header-title has-text-light">
|
||||||
|
<span class="icon"><i class="fa fa-exclamation-triangle"></i></span>
|
||||||
|
<span>Your profile page is too private</span>
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="card-content">
|
||||||
|
<p class="block">
|
||||||
|
You are considered to be a <strong>Shy Account</strong> because your profile and
|
||||||
|
photos are all set to Private or Friends-only visibility, so that to other members
|
||||||
|
of {{PrettyTitle}} you appear like a blank, faceless profile.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="block">
|
||||||
|
While in this restricted state, you are grouped into a cohort with other members who
|
||||||
|
are as shy as you are and have limited contact options to connect with our other,
|
||||||
|
{{PrettyTitle}} members who are sharing their nudes on public.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="block">
|
||||||
|
<a href="/faq#shy-faqs">Click here to learn more</a> about your Shy Account. To
|
||||||
|
remedy this, please see the following steps:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul class="menu-list block">
|
||||||
|
<li>
|
||||||
|
<a href="/settings">
|
||||||
|
{{if eq .CurrentUser.Visibility "public"}}
|
||||||
|
<span class="icon"><i class="fa fa-circle-check has-text-success"></i></span>
|
||||||
|
{{else}}
|
||||||
|
<span class="icon"><i class="fa fa-circle has-text-danger"></i></span>
|
||||||
|
{{end}}
|
||||||
|
<span>
|
||||||
|
Have your profile visibility set to <strong>Public</strong>.
|
||||||
|
{{if not (eq .CurrentUser.Visibility "public")}}
|
||||||
|
<span class="icon"><i class="fa fa-external-link"></i></span>
|
||||||
|
{{end}}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a href="/photo/u/{{.CurrentUser.Username}}">
|
||||||
|
{{if .HasPublicPhoto}}
|
||||||
|
<span class="icon"><i class="fa fa-circle-check has-text-success"></i></span>
|
||||||
|
{{else}}
|
||||||
|
<span class="icon"><i class="fa fa-circle has-text-danger"></i></span>
|
||||||
|
{{end}}
|
||||||
|
<span>
|
||||||
|
Have at least one <strong>Public</strong> photo on your profile.
|
||||||
|
{{if not .HasPublicPhoto}}
|
||||||
|
<span class="icon"><i class="fa fa-external-link"></i></span>
|
||||||
|
{{end}}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
<div class="card block">
|
<div class="card block">
|
||||||
<header class="card-header has-background-link">
|
<header class="card-header has-background-link">
|
||||||
<p class="card-header-title has-text-light">My Account</p>
|
<p class="card-header-title has-text-light">My Account</p>
|
||||||
|
|
|
@ -228,6 +228,29 @@
|
||||||
{{if .GetProfileField "orientation"}}
|
{{if .GetProfileField "orientation"}}
|
||||||
<span class="mr-2">{{.GetProfileField "orientation"}}</span>
|
<span class="mr-2">{{.GetProfileField "orientation"}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
<!-- Show a subfooter based on ordered by -->
|
||||||
|
{{if eq $Root.Sort "last_login_at desc"}}
|
||||||
|
<div>
|
||||||
|
<small>
|
||||||
|
Last logged in:
|
||||||
|
<span title="On {{.LastLoginAt.Format "Jan _2 2006 15:04:05 MST"}}">
|
||||||
|
{{SincePrettyCoarse .LastLoginAt}} ago
|
||||||
|
</span>
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if eq $Root.Sort "created_at desc"}}
|
||||||
|
<div>
|
||||||
|
<small>
|
||||||
|
Member since:
|
||||||
|
<span title="On {{.CreatedAt.Format "Jan _2 2006 15:04:05 MST"}}">
|
||||||
|
{{SincePrettyCoarse .CreatedAt}} ago
|
||||||
|
</span>
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div><!-- media-block -->
|
</div><!-- media-block -->
|
||||||
|
|
|
@ -26,6 +26,15 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="block p-4">
|
<div class="block p-4">
|
||||||
|
{{if .IsShyUser}}
|
||||||
|
<div class="notification is-danger is-light">
|
||||||
|
<i class="fa fa-exclamation-triangle"></i> You have a <strong>Shy Account</strong> and you may not enter
|
||||||
|
the chat room at this time, where our {{PrettyTitle}} members may be sharing their cameras. You are
|
||||||
|
sharing no public photos with the community, so you get limited access to ours.
|
||||||
|
<a href="/faq#shy-faqs">Learn more about how to resolve this issue. <small class="fa fa-external-link"></small></a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p>
|
<p>
|
||||||
{{PrettyTitle}} has a new chat room! Come and check it out. It features some public rooms, direct
|
{{PrettyTitle}} has a new chat room! Come and check it out. It features some public rooms, direct
|
||||||
|
@ -60,6 +69,10 @@
|
||||||
yet for Safari. Use Firefox or Chrome (or other Chromium browser of your choice) for better odds
|
yet for Safari. Use Firefox or Chrome (or other Chromium browser of your choice) for better odds
|
||||||
of video support.
|
of video support.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Unfortunately, the chat room does not work on iPhones or iPads at this time.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -53,6 +53,15 @@
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#shy-faqs">Shy Account FAQs</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#shy-restrictions">What restrictions apply to Shy Accounts?</a></li>
|
||||||
|
<li><a href="#shy-cando">Why can Shy Accounts do?</a></li>
|
||||||
|
<li><a href="#shy-fixit">How do I fix it?</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="#technical-faqs">Technical FAQs</a>
|
<a href="#technical-faqs">Technical FAQs</a>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -499,6 +508,123 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<h1 id="shy-faqs"><i class="fa fa-ghost"></i> Shy Account FAQs</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
One of the things that {{PrettyTitle}} wishes to avoid is the dreaded "blank profile"
|
||||||
|
that slides into our DMs and gets creepy and weird on us. You are encouraged to participate
|
||||||
|
on this site and share at least one public photo with the community. You may opt to have
|
||||||
|
only "G-rated face pics" on public and nudes on private, or keep your face on private and
|
||||||
|
share some body shots with your face cropped out on public - but share at least one good
|
||||||
|
picture on public.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
When your profile page or photos are <em>all</em> set to Private or Friends-only, you will
|
||||||
|
be considered to have a <strong>Shy Account.</strong>
|
||||||
|
A Shy Account can still interact on the forums but will have limited options to
|
||||||
|
interact with non-restricted ({{PrettyTitle}}) members.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 id="shy-restrictions">What restrictions apply to Shy Accounts?</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The limits placed on Shy Accounts are:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
The <i class="fa fa-image"></i> <strong>Site Gallery</strong> will only show you pictures
|
||||||
|
of people equally as shy as you are. That is, you may see your own pictures and those of
|
||||||
|
Friends you have added, but you don't see public shares of {{PrettyTitle}} people
|
||||||
|
who aren't your friends.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong><i class="fa fa-envelope"></i> Messages:</strong> you may slide into the DMs only
|
||||||
|
of other shy members but you can <strong>not</strong> initiate DMs with a {{PrettyTitle}} one who is not on
|
||||||
|
your Friends list. At their own discretion, they may initiate a chat with you and then you can reply to them.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
You can view anybody's <i class="fa fa-user"></i> <strong>Profile Page</strong> but you
|
||||||
|
can <strong>not</strong> see a {{PrettyTitle}} account's Photo Gallery unless they are
|
||||||
|
your Friend or have shared their private pictures with you.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
You can not join the <i class="fa fa-message"></i> <strong>Chat Room</strong>. You guys
|
||||||
|
may soon get your own chat room, though. Many of us {{PrettyTitle}} nudists would not
|
||||||
|
enjoy our webcams being watched by blank profiles.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The idea is to keep the shy members isolated from the non-shy ones. We nudists are sharing
|
||||||
|
what we can and we don't want creepers to be ogling our nudes and not sharing anything in
|
||||||
|
return. If all your pics are private, you look like a blank profile to us - and you will be
|
||||||
|
kept with the other blank profiles until you choose to participate.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 id="shy-cando">What <em>can</em> Shy Accounts do?</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
There are still a lot things you <strong>can</strong> do with your <strong>certified</strong>
|
||||||
|
but Shy Account:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
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.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
You can send a <i class="fa fa-user"></i> <strong>Friend request</strong> to anybody and if they accept you
|
||||||
|
can see their Photo Gallery and pictures appear in the Site Gallery.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
You can send <i class="fa fa-envelope"></i> <strong>DMs</strong> to other shy people like yourself, and reply
|
||||||
|
to DMs that were sent by anybody who messages you first.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
You can browse the <i class="fa fa-people-group"></i> <strong>Member Directory</strong> and view public
|
||||||
|
profile pages and send friend requests to whoever.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3 id="shy-fixit">How do I fix it?</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Leaving <strong>Shy Account</strong> territory is easy:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>Don't have your profile page set to <strong>private.</strong> Only logged-in, certified members can see your page, anyway!</li>
|
||||||
|
<li>
|
||||||
|
Have at least one <strong>public</strong> picture to share with the class. Ideally, it will be your profile picture that
|
||||||
|
shows your face, but we'll settle for a good headless body shot. We're all sharing our nudes here, we'd like it if you
|
||||||
|
participated as well.
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If you are new to all of this, here are some ideas how you can manage your
|
||||||
|
photo gallery to have at least one <strong>public</strong> picture to share:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>You could have a single, "G-rated" face pic as your Public profile picture, and have the others on Friends-only or Private.</li>
|
||||||
|
<li>
|
||||||
|
You could upload all your "G-rated" face pics as Public, and have nudes (with your face cropped out if you need) on Friends-only
|
||||||
|
or Private.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
You could have a non-public profile pic along with "anonymized" nudes on Public, full nudes w/ face on Friends-only, and
|
||||||
|
sexual stuff on Private that you unlock on a per-person basis.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
You can <strong>opt-out</strong> of the Site Gallery by un-checking the Gallery box on the upload page. Your public
|
||||||
|
photos then would only been seen if somebody clicks <em>through</em> your profile page to see your gallery.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<h1 id="technical-faqs">Technical FAQs</h1>
|
<h1 id="technical-faqs">Technical FAQs</h1>
|
||||||
|
|
||||||
<h3 id="why">Why did you build a custom website?</h3>
|
<h3 id="why">Why did you build a custom website?</h3>
|
||||||
|
|
|
@ -72,6 +72,7 @@
|
||||||
|
|
||||||
<!-- Reusable pager -->
|
<!-- Reusable pager -->
|
||||||
{{define "pager"}}
|
{{define "pager"}}
|
||||||
|
{{if .Pager.Total}}
|
||||||
<nav class="pagination" role="navigation" aria-label="pagination">
|
<nav class="pagination" role="navigation" aria-label="pagination">
|
||||||
<a class="pagination-previous{{if not .Pager.HasPrevious}} is-disabled{{end}}" title="Previous"
|
<a class="pagination-previous{{if not .Pager.HasPrevious}} is-disabled{{end}}" title="Previous"
|
||||||
href="{{.Request.URL.Path}}?{{QueryPlus "page" .Pager.Previous}}">Previous</a>
|
href="{{.Request.URL.Path}}?{{QueryPlus "page" .Pager.Previous}}">Previous</a>
|
||||||
|
@ -91,6 +92,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
<!-- Main content template -->
|
<!-- Main content template -->
|
||||||
{{define "content"}}
|
{{define "content"}}
|
||||||
|
@ -162,16 +164,34 @@
|
||||||
<button class="modal-close is-large" aria-label="close"></button>
|
<button class="modal-close is-large" aria-label="close"></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Shy User alert banner (Site Gallery) -->
|
||||||
|
{{if and .IsSiteGallery .IsShyUser}}
|
||||||
|
<div class="notification is-danger is-light">
|
||||||
|
<i class="fa fa-exclamation-triangle"></i> You have a <strong>Shy Account</strong> so you will only see
|
||||||
|
pictures of you and your friends here. <a href="/faq#shy-faqs">Learn more <small class="fa fa-external-link"></small></a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<!-- Shy User alert banner (User Gallery - IsShyFrom) -->
|
||||||
|
{{if .IsShyFrom}}
|
||||||
|
<div class="notification is-danger is-light">
|
||||||
|
<i class="fa fa-exclamation-triangle"></i> You have a <strong>Shy Account</strong> and you are not friends
|
||||||
|
with this person so can not see their gallery. <a href="/faq#shy-faqs">Learn more <small class="fa fa-external-link"></small></a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<div class="level{{if .IsOwnPhotos}}mb-0{{end}}">
|
<div class="level{{if .IsOwnPhotos}}mb-0{{end}}">
|
||||||
<div class="level-left">
|
<div class="level-left">
|
||||||
<div class="level-item">
|
<div class="level-item">
|
||||||
|
{{if .Pager.Total}}
|
||||||
<span>
|
<span>
|
||||||
Found <strong>{{.Pager.Total}}</strong> photo{{Pluralize64 .Pager.Total}} (page {{.Pager.Page}} of {{.Pager.Pages}}).
|
Found <strong>{{.Pager.Total}}</strong> photo{{Pluralize64 .Pager.Total}} (page {{.Pager.Page}} of {{.Pager.Pages}}).
|
||||||
{{if .ExplicitCount}}
|
{{if .ExplicitCount}}
|
||||||
{{.ExplicitCount}} explicit photo{{Pluralize64 .ExplicitCount}} hidden per your settings.
|
{{.ExplicitCount}} explicit photo{{Pluralize64 .ExplicitCount}} hidden per your settings.
|
||||||
{{end}}
|
{{end}}
|
||||||
</span>
|
</span>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user