DM Privacy + Settings Page Tabs
* Refactor the Settings page into a tabbed UI to reduce confusion with all the different forms and save buttons * Add a DM Privacy setting to your page * Update the About page
This commit is contained in:
parent
0f6b627156
commit
45cb4d260e
|
@ -64,6 +64,9 @@ var (
|
|||
"interests",
|
||||
"music_movies",
|
||||
"hide_age",
|
||||
|
||||
// Site prefs
|
||||
"dm_privacy",
|
||||
}
|
||||
|
||||
// Choices for the Contact Us subject
|
||||
|
|
|
@ -46,12 +46,16 @@ func Settings() http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
// URL hashtag to redirect to
|
||||
var hashtag string
|
||||
|
||||
// Are we POSTing?
|
||||
if r.Method == http.MethodPost {
|
||||
intent := r.PostFormValue("intent")
|
||||
switch intent {
|
||||
case "profile":
|
||||
// Setting profile values.
|
||||
hashtag = "#profile"
|
||||
var (
|
||||
displayName = r.PostFormValue("display_name")
|
||||
dob = r.PostFormValue("dob")
|
||||
|
@ -95,6 +99,7 @@ func Settings() http.HandlerFunc {
|
|||
|
||||
session.Flash(w, r, "Profile settings updated!")
|
||||
case "preferences":
|
||||
hashtag = "#prefs"
|
||||
var (
|
||||
explicit = r.PostFormValue("explicit") == "true"
|
||||
visibility = models.UserVisibility(r.PostFormValue("visibility"))
|
||||
|
@ -109,12 +114,16 @@ func Settings() http.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
// Set profile field prefs.
|
||||
user.SetProfileField("dm_privacy", r.PostFormValue("dm_privacy"))
|
||||
|
||||
if err := user.Save(); err != nil {
|
||||
session.FlashError(w, r, "Failed to save user to database: %s", err)
|
||||
}
|
||||
|
||||
session.Flash(w, r, "Website preferences updated!")
|
||||
case "settings":
|
||||
hashtag = "#account"
|
||||
var (
|
||||
oldPassword = r.PostFormValue("old_password")
|
||||
changeEmail = strings.TrimSpace(strings.ToLower(r.PostFormValue("change_email")))
|
||||
|
@ -197,7 +206,7 @@ func Settings() http.HandlerFunc {
|
|||
session.FlashError(w, r, "Unknown POST intent value. Please try again.")
|
||||
}
|
||||
|
||||
templates.Redirect(w, r.URL.Path)
|
||||
templates.Redirect(w, r.URL.Path+hashtag+".")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -72,9 +72,10 @@ func Compose() http.HandlerFunc {
|
|||
// 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()
|
||||
theyreShy = user.IsShy()
|
||||
isShyFrom = currentUser.IsShyFrom(user) || (imShy && !models.AreFriends(currentUser.ID, user.ID))
|
||||
imShy = currentUser.IsShy()
|
||||
theyreShy = user.IsShy()
|
||||
areFriends = models.AreFriends(currentUser.ID, user.ID)
|
||||
isShyFrom = currentUser.IsShyFrom(user) || (imShy && !areFriends)
|
||||
)
|
||||
if imShy && isShyFrom && !theyreShy && !user.IsAdmin {
|
||||
session.FlashError(w, r, "You have a Shy Account and can not initiate Direct Messages with a non-shy member.")
|
||||
|
@ -82,6 +83,22 @@ func Compose() http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
// Does the recipient have a privacy control on their DMs?
|
||||
switch user.GetProfileField("dm_privacy") {
|
||||
case "friends":
|
||||
if !areFriends && !currentUser.IsAdmin {
|
||||
session.FlashError(w, r, "This user only wants to receive new DMs from their friends.")
|
||||
templates.Redirect(w, "/u/"+user.Username)
|
||||
return
|
||||
}
|
||||
case "nobody":
|
||||
if !currentUser.IsAdmin {
|
||||
session.FlashError(w, r, "This user's DMs are closed and they do not want any new conversations.")
|
||||
templates.Redirect(w, "/u/"+user.Username)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var vars = map[string]interface{}{
|
||||
"User": user,
|
||||
}
|
||||
|
|
|
@ -389,6 +389,7 @@ func (u *User) SetProfileField(name, value string) {
|
|||
return
|
||||
}
|
||||
|
||||
log.Debug("User(%s): append ProfileField %s", u.Username, name)
|
||||
u.ProfileField = append(u.ProfileField, ProfileField{
|
||||
Name: name,
|
||||
Value: value,
|
||||
|
|
|
@ -80,6 +80,155 @@
|
|||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>What features does this site have?</h2>
|
||||
|
||||
<p>
|
||||
We have so far:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
A <a href="#webcam-chat-room"><strong>Webcam Chat Room</strong></a> where you can chat, share images,
|
||||
and go on camera with other website members. 'Explicit' cameras are allowed, just mark
|
||||
your camera feed as such so other members might know what they're getting into!
|
||||
Read more about the <a href="#webcam-chat-room">chat room</a>, below.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Forums</strong> where you can meet and converse with members of the
|
||||
site around a variety of themes and topics.
|
||||
</li>
|
||||
<li>
|
||||
A <strong>Site Photo Gallery</strong> where members may opt-in their profile gallery
|
||||
photos to be seen by the whole site (or at least to their friends when they look at
|
||||
the Site Gallery).
|
||||
</li>
|
||||
<li>
|
||||
<strong>Friend Requests</strong> so you can make some new connections through this site.
|
||||
You can also tag some of your photos as "Friends only" and make sure only your approved
|
||||
friends can see those!
|
||||
</li>
|
||||
<li>
|
||||
<strong>Profile pages & Photo Galleries</strong>: members may upload up to 100 photos
|
||||
on their page and fill out a profile with the usual details.
|
||||
</li>
|
||||
<li>
|
||||
A <strong>Member Directory</strong> to browse and search for people on the site.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
We also have some <strong>privacy controls</strong> that members on any stage of their
|
||||
nudist journey may enjoy to have some control over what they share and with whom:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
By default, <strong>only logged-in members</strong> can see your profile page or
|
||||
photos at all. (You may opt to have a "slightly public" profile page that you could
|
||||
link to from your Twitter, which reveals little information beyond your username
|
||||
and profile pic).
|
||||
</li>
|
||||
<li>
|
||||
When you upload a photo you may mark it as for <strong>"Friends only"</strong> or <strong>"Private."</strong> This way
|
||||
you can limit the audience of certain pictures to only your approved friendships, or
|
||||
in the case of Private photos, to specific members to whom you grant access. You may
|
||||
also revoke your private photos from one or all members at once.
|
||||
</li>
|
||||
<li>
|
||||
If you are concerned about unsolicited messages by randoms, you may limit <strong>who is allowed
|
||||
to slide into your DMs</strong> to "Friends only" or even to "Nobody." People may always reply to
|
||||
messages that you send them first, but if they haven't contacted you before, you can prevent
|
||||
them from doing so. "Nobody" is like having your DMs closed but you can still continue conversations
|
||||
you had open already.
|
||||
</li>
|
||||
<li>
|
||||
You may mark your whole profile page as "private" and then only your Friends may see its
|
||||
contents. But, this will make you a "shy account" and see the next point.
|
||||
</li>
|
||||
<li>
|
||||
Members who are <em>very</em> shy (they're Certified so the admin has seen their face,
|
||||
but they keep all their photos or profile on Private so they look to others like a 'blank
|
||||
profile') are considered by the site to be <a href="/faq#shy-faqs">"Shy Accounts"</a> and
|
||||
they can <em>not</em> slide into your DMs if you are sharing photos on public but they are
|
||||
not. They also won't see <em>any</em> of your photos (unless you are friends). See the
|
||||
<a href="/faq#shy-faqs">FAQs</a> for more details.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4 id="webcam-chat-room">A Webcam Chat Room</h4>
|
||||
|
||||
<p>
|
||||
The chat room is a completely custom-built app for {{PrettyTitle}} (and it's
|
||||
<a href="#open-source">open source</a> too!)
|
||||
and here are some of its features in detail:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
It's a classic chat room featuring multiple public channels, Private Messages/DMs,
|
||||
a list of online chatters and links to see their profile or open their webcam
|
||||
if they're sharing.
|
||||
</li>
|
||||
<li>
|
||||
You may broadcast your webcam and microphone, and other users in the
|
||||
room may tune in and watch your camera.
|
||||
</li>
|
||||
<li>
|
||||
You are permitted to get "sexual" on camera if you want. Just mark your camera
|
||||
as <span class="has-text-danger">'Explicit'</span> so other chatters may know what
|
||||
they're getting into before they click in.
|
||||
</li>
|
||||
<li>
|
||||
You could have "infinite" cameras open with other chatters: as long as your
|
||||
screen size and network can support it (there is no enforced limit, as it makes
|
||||
no difference to my chat server how many cams you open -- the connections are
|
||||
usually peer-to-peer!)
|
||||
</li>
|
||||
<li>
|
||||
You can see who all is watching your camera, and you can "boot" somebody
|
||||
off if you don't want them to watch. When booted, they will not be able to
|
||||
watch again, and your camera will appear 'offline' to them so they can't
|
||||
be sure you didn't simply turn your camera off.
|
||||
</li>
|
||||
<li>
|
||||
You can 'mute' people if you no longer want to see their messages in chat
|
||||
or receive any further DMs from them (and this also prevents them from
|
||||
seeing your camera - like a 'boot' they won't see if your camera is even
|
||||
broadcasting!)
|
||||
</li>
|
||||
<li>
|
||||
You can upload photos (and GIFs up to 8 MB!) to share with the chat room
|
||||
or over Direct Messages.
|
||||
</li>
|
||||
<li>
|
||||
All chatters are guaranteed to be <a href="/faq#certification-faqs">"Certified"</a>
|
||||
real human beings and have at least one 'public' photo on their page that you
|
||||
could see. Certification is <strong>required</strong> for <em>all</em> site
|
||||
features (see <a href="/faq#uncertified">what non-certified members can even do</a>)
|
||||
but additionally the "certified, <a href="/faq#shy-faqs">but shy</a>" members are
|
||||
not allowed in the chat room <strong>at all.</strong>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
A unique feature of the chat room are the <strong>mutual webcam options</strong>.
|
||||
Some nudists feel weirded out if they are on camera and they are being watched
|
||||
by some silent lurker who isn't sharing their own camera in return. On the
|
||||
{{PrettyTitle}} chat room, you can opt-in to "mutual webcam" options if you like:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
You can require your webcam viewers to first be sharing <em>their own</em>
|
||||
webcam in return, before they can open yours.
|
||||
</li>
|
||||
<li>
|
||||
You may also automatically open the viewer's webcam (if they are broadcasting)
|
||||
when they click in to see your camera. This can save you a click of needing to
|
||||
open the camera of the person who just opened yours.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>Who is this site for?</h2>
|
||||
|
||||
<p>
|
||||
|
@ -128,15 +277,17 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content block pt-1">
|
||||
<div class="content block pt-1" id="open-source">
|
||||
<h3><i class="fa fa-code"></i> This website is open source!</h3>
|
||||
<p>
|
||||
If you would like to see the source code or contribute bug fixes or new features, the
|
||||
source code behind this website is available at
|
||||
<a href="https://code.nonshy.com/nonshy/website" target="_blank">code.nonshy.com</a>.
|
||||
The chat room is an independent open source app that you may use with <em>your</em>
|
||||
website too and it's called <a href="https://git.kirsle.net/apps/BareRTC">BareRTC</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
|
@ -155,16 +155,23 @@
|
|||
</form>
|
||||
</div>
|
||||
|
||||
<div class="column is-narrow has-text-centered">
|
||||
<a href="/messages/compose?to={{.User.Username}}" class="button is-fullwidth">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa fa-message"></i>
|
||||
<!-- DM button -->
|
||||
{{if and (eq (.User.GetProfileField "dm_privacy") "friends") (not (eq .IsFriend "approved")) (not .CurrentUser.IsAdmin)}}
|
||||
<!-- Only friends can send them a DM -->
|
||||
{{else if and (eq (.User.GetProfileField "dm_privacy") "nobody") (not .CurrentUser.IsAdmin)}}
|
||||
<!-- They set "Nobody" can send them a DM -->
|
||||
{{else}}
|
||||
<div class="column is-narrow has-text-centered">
|
||||
<a href="/messages/compose?to={{.User.Username}}" class="button is-fullwidth">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa fa-message"></i>
|
||||
</span>
|
||||
<span>Message</span>
|
||||
</span>
|
||||
<span>Message</span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<!-- Like button -->
|
||||
{{if not .IsPrivate}}
|
||||
|
@ -431,4 +438,4 @@
|
|||
</div>
|
||||
{{end}}<!-- not IsPrivate -->
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
|
@ -12,376 +12,537 @@
|
|||
{{ $User := .CurrentUser }}
|
||||
|
||||
<div class="block p-4">
|
||||
<div class="columns">
|
||||
<div class="tabs is-boxed">
|
||||
<ul>
|
||||
<li class="is-active">
|
||||
<a href="/settings#profile" class="nonshy-tab-button">
|
||||
Profile
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/settings#prefs" class="nonshy-tab-button">
|
||||
Preferences
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<div class="column is-hidden-tablet p-4">
|
||||
<label class="label">Jump to section:</label>
|
||||
<ul class="menu-list">
|
||||
<li><a href="#profile">My Profile</a></li>
|
||||
<li><a href="#verification">Verification Photo</a></li>
|
||||
<li><a href="#prefs">Website Preferences</a></li>
|
||||
<li><a href="#account">Account Settings <small class="has-text-grey ml-2">Email & password</small></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<li>
|
||||
<a href="/settings#account" class="nonshy-tab-button">
|
||||
Account
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<div class="card" id="profile">
|
||||
<header class="card-header has-background-link">
|
||||
<p class="card-header-title has-text-light">
|
||||
<i class="fa fa-user pr-2"></i>
|
||||
My Profile
|
||||
</p>
|
||||
</header>
|
||||
<div class="card" id="profile">
|
||||
<header class="card-header has-background-link">
|
||||
<p class="card-header-title has-text-light">
|
||||
<i class="fa fa-user pr-2"></i>
|
||||
My Profile
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<form method="POST" action="/settings">
|
||||
<input type="hidden" name="intent" value="profile">
|
||||
{{InputCSRF}}
|
||||
<form method="POST" action="/settings">
|
||||
<input type="hidden" name="intent" value="profile">
|
||||
{{InputCSRF}}
|
||||
|
||||
<div class="card-content">
|
||||
<p class="block">
|
||||
The fields here are shown on your <a href="/u/{{.CurrentUser.Username}}">profile page</a>
|
||||
and are all optional. Fields with a <i class="fa fa-lock"></i> icon are not shown on
|
||||
your page but may drive some data that is (e.g., your current age derived from your birthdate).
|
||||
<div class="card-content">
|
||||
<p class="block">
|
||||
The fields here are shown on your <a href="/u/{{.CurrentUser.Username}}">profile page</a>
|
||||
and are all optional. Fields with a <i class="fa fa-lock"></i> icon are not shown on
|
||||
your page but may drive some data that is (e.g., your current age derived from your birthdate).
|
||||
</p>
|
||||
|
||||
<div class="columns">
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="display_name">Display Name</label>
|
||||
<input type="text" class="input"
|
||||
id="display_name"
|
||||
name="display_name"
|
||||
placeholder="John Doe"
|
||||
value="{{or $User.Name ""}}">
|
||||
</div>
|
||||
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="dob">Birthdate <i class="fa fa-lock"></i></label>
|
||||
<input type="date" class="input{{if not $User.Birthdate.IsZero}} cursor-not-allowed{{end}}"
|
||||
id="dob"
|
||||
name="dob"
|
||||
value="{{if not $User.Birthdate.IsZero}}{{$User.Birthdate.Format "2006-01-02"}}{{end}}"
|
||||
required
|
||||
{{if not $User.Birthdate.IsZero}}readonly{{end}}>
|
||||
<p class="help">
|
||||
Used to show your age on your profile.
|
||||
{{if not $User.Birthdate.IsZero}}
|
||||
If you entered a wrong birthdate, <a href="/contact">contact</a> support to change it.
|
||||
{{end}}
|
||||
</p>
|
||||
|
||||
<div class="columns">
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="display_name">Display Name</label>
|
||||
<input type="text" class="input"
|
||||
id="display_name"
|
||||
name="display_name"
|
||||
placeholder="John Doe"
|
||||
value="{{or $User.Name ""}}">
|
||||
</div>
|
||||
<!-- Don't show age checkbox -->
|
||||
<label class="checkbox">
|
||||
<input type="checkbox"
|
||||
name="hide_age"
|
||||
value="true"
|
||||
{{if eq ($User.GetProfileField "hide_age") "true"}}checked{{end}}>
|
||||
Don't show my age on my profile
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="dob">Birthdate <i class="fa fa-lock"></i></label>
|
||||
<input type="date" class="input{{if not $User.Birthdate.IsZero}} cursor-not-allowed{{end}}"
|
||||
id="dob"
|
||||
name="dob"
|
||||
value="{{if not $User.Birthdate.IsZero}}{{$User.Birthdate.Format "2006-01-02"}}{{end}}"
|
||||
required
|
||||
{{if not $User.Birthdate.IsZero}}readonly{{end}}>
|
||||
<p class="help">
|
||||
Used to show your age on your profile.
|
||||
{{if not $User.Birthdate.IsZero}}
|
||||
If you entered a wrong birthdate, <a href="/contact">contact</a> support to change it.
|
||||
{{end}}
|
||||
</p>
|
||||
|
||||
<!-- Don't show age checkbox -->
|
||||
<label class="checkbox">
|
||||
<input type="checkbox"
|
||||
name="hide_age"
|
||||
value="true"
|
||||
{{if eq ($User.GetProfileField "hide_age") "true"}}checked{{end}}>
|
||||
Don't show my age on my profile
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="columns">
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="gender">Gender</label>
|
||||
<div class="select is-fullwidth">
|
||||
<select id="gender" name="gender">
|
||||
<option value="">No answer</option>
|
||||
{{range .Enum.Gender}}
|
||||
<option value="{{.}}"{{if eq ($User.GetProfileField "gender") .}} selected{{end}}>{{.}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="pronouns">Pronouns</label>
|
||||
<input type="text" class="input"
|
||||
id="pronouns"
|
||||
name="pronouns"
|
||||
maxlength="30"
|
||||
value="{{$User.GetProfileField "pronouns"}}">
|
||||
<p class="help">e.g. he/him; she/her</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="columns">
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="city">City/Location</label>
|
||||
<input type="text" class="input"
|
||||
id="city"
|
||||
name="city"
|
||||
value="{{$User.GetProfileField "city"}}">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="job">Job/Occupation</label>
|
||||
<input type="text" class="input"
|
||||
id="job"
|
||||
name="job"
|
||||
value="{{$User.GetProfileField "job"}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="columns">
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="marital_status">Marital Status</label>
|
||||
<div class="select is-fullwidth">
|
||||
<select id="marital_status" name="marital_status">
|
||||
<option value="">No answer</option>
|
||||
{{range .Enum.MaritalStatus}}
|
||||
<option value="{{.}}"{{if eq ($User.GetProfileField "marital_status") .}} selected{{end}}>{{.}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="relationship_type">Relationship Type</label>
|
||||
<div class="select is-fullwidth">
|
||||
<select id="relationship_type" name="relationship_type">
|
||||
<option value="">No answer</option>
|
||||
{{range .Enum.RelationshipType}}
|
||||
<option value="{{.}}"{{if eq ($User.GetProfileField "relationship_type") .}} selected{{end}}>{{.}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="columns">
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="orientation">Orientation</label>
|
||||
<div class="select is-fullwidth">
|
||||
<select id="orientation" name="orientation">
|
||||
<option value="">No answer</option>
|
||||
{{range .Enum.Orientation}}
|
||||
<option value="{{.}}"{{if eq ($User.GetProfileField "orientation") .}} selected{{end}}>{{.}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label">Here For</label>
|
||||
<div class="columns is-multiline pb-5">
|
||||
{{range .Enum.HereFor}}
|
||||
<div class="column is-one-third pb-0">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox"
|
||||
name="here_for"
|
||||
value="{{.}}"
|
||||
{{if $User.ProfileFieldIn "here_for" .}}checked{{end}}>
|
||||
{{.}}
|
||||
</label>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="gender">Gender</label>
|
||||
<div class="select is-fullwidth">
|
||||
<select id="gender" name="gender">
|
||||
<option value="">No answer</option>
|
||||
{{range .Enum.Gender}}
|
||||
<option value="{{.}}"{{if eq ($User.GetProfileField "gender") .}} selected{{end}}>{{.}}</option>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label" for="about_me">About Me</label>
|
||||
<textarea class="textarea" cols="60" rows="4"
|
||||
id="about_me"
|
||||
name="about_me"
|
||||
placeholder="A little blurb about myself">{{$User.GetProfileField "about_me"}}</textarea>
|
||||
<p class="help">
|
||||
Write a bit about yourself. <a href="/markdown" target="_blank">Markdown formatting</a> is supported here.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label" for="interests">My Interests</label>
|
||||
<textarea class="textarea" cols="60" rows="4"
|
||||
id="interests"
|
||||
name="interests"
|
||||
placeholder="What kinds of things make you curious?">{{$User.GetProfileField "interests"}}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label" for="music_movies">Music/Bands/Movies</label>
|
||||
<textarea class="textarea" cols="60" rows="4"
|
||||
id="music_movies"
|
||||
name="music_movies"
|
||||
placeholder="What is your style of music or movie?">{{$User.GetProfileField "music_movies"}}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<button type="submit" class="button is-primary">
|
||||
Save Profile Settings
|
||||
</button>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="pronouns">Pronouns</label>
|
||||
<input type="text" class="input"
|
||||
id="pronouns"
|
||||
name="pronouns"
|
||||
maxlength="30"
|
||||
value="{{$User.GetProfileField "pronouns"}}">
|
||||
<p class="help">e.g. he/him; she/her</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Website Preferences -->
|
||||
<form method="POST" action="/settings">
|
||||
<input type="hidden" name="intent" value="preferences">
|
||||
{{InputCSRF}}
|
||||
<div class="columns">
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="city">City/Location</label>
|
||||
<input type="text" class="input"
|
||||
id="city"
|
||||
name="city"
|
||||
value="{{$User.GetProfileField "city"}}">
|
||||
</div>
|
||||
|
||||
<div class="card mb-5" id="prefs">
|
||||
<header class="card-header has-background-success">
|
||||
<p class="card-header-title has-text-dark-dark">
|
||||
<i class="fa fa-square-check pr-2"></i>
|
||||
Website Preferences
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<div class="card-content">
|
||||
<div class="field">
|
||||
<label class="label">Profile Visibility</label>
|
||||
<label class="checkbox">
|
||||
<input type="radio"
|
||||
name="visibility"
|
||||
value="public"
|
||||
{{if eq .CurrentUser.Visibility "public"}}checked{{end}}>
|
||||
Public + Login Required
|
||||
</label>
|
||||
<p class="help">
|
||||
The default is that users must be logged-in to even look at your profile
|
||||
page. If your profile URL (/u/{{.CurrentUser.Username}}) is visited by a
|
||||
logged-out browser, they are prompted to log in.
|
||||
</p>
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="job">Job/Occupation</label>
|
||||
<input type="text" class="input"
|
||||
id="job"
|
||||
name="job"
|
||||
value="{{$User.GetProfileField "job"}}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label class="checkbox mt-2">
|
||||
<input type="radio"
|
||||
name="visibility"
|
||||
value="external"
|
||||
{{if eq .CurrentUser.Visibility "external"}}checked{{end}}>
|
||||
Public + Limited Logged-out View
|
||||
</label>
|
||||
<p class="help">
|
||||
Your profile is fully visible to logged-in users, but if a logged-out browser
|
||||
visits your page they will see a very minimal view: only your profile picture
|
||||
and display name are shown.
|
||||
<a href="/u/{{.CurrentUser.Username}}?view=external" target="_blank">Preview <i class="fa fa-external-link"></i></a>
|
||||
</p>
|
||||
|
||||
<label class="checkbox mt-2">
|
||||
<input type="radio"
|
||||
name="visibility"
|
||||
value="private"
|
||||
{{if eq .CurrentUser.Visibility "private"}}checked{{end}}>
|
||||
Mark my profile page as "private"
|
||||
</label>
|
||||
<p class="help">
|
||||
If you check this box then only friends who you have approved are able to
|
||||
see your profile page and gallery. Your gallery photos also will NOT appear
|
||||
on the Site Gallery page. If your profile page is visited by a logged-out
|
||||
viewer, they are prompted to log in.
|
||||
</p>
|
||||
<div class="columns">
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="marital_status">Marital Status</label>
|
||||
<div class="select is-fullwidth">
|
||||
<select id="marital_status" name="marital_status">
|
||||
<option value="">No answer</option>
|
||||
{{range .Enum.MaritalStatus}}
|
||||
<option value="{{.}}"{{if eq ($User.GetProfileField "marital_status") .}} selected{{end}}>{{.}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label">Explicit Content Filter</label>
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="relationship_type">Relationship Type</label>
|
||||
<div class="select is-fullwidth">
|
||||
<select id="relationship_type" name="relationship_type">
|
||||
<option value="">No answer</option>
|
||||
{{range .Enum.RelationshipType}}
|
||||
<option value="{{.}}"{{if eq ($User.GetProfileField "relationship_type") .}} selected{{end}}>{{.}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="columns">
|
||||
<div class="column field is-half">
|
||||
<label class="label" for="orientation">Orientation</label>
|
||||
<div class="select is-fullwidth">
|
||||
<select id="orientation" name="orientation">
|
||||
<option value="">No answer</option>
|
||||
{{range .Enum.Orientation}}
|
||||
<option value="{{.}}"{{if eq ($User.GetProfileField "orientation") .}} selected{{end}}>{{.}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label">Here For</label>
|
||||
<div class="columns is-multiline pb-5">
|
||||
{{range .Enum.HereFor}}
|
||||
<div class="column is-one-third pb-0">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox"
|
||||
name="explicit"
|
||||
value="true"
|
||||
{{if .CurrentUser.Explicit}}checked{{end}}>
|
||||
Show explicit content
|
||||
name="here_for"
|
||||
value="{{.}}"
|
||||
{{if $User.ProfileFieldIn "here_for" .}}checked{{end}}>
|
||||
{{.}}
|
||||
</label>
|
||||
<p class="help">
|
||||
Check this box if you are OK seeing explicit content on this site, which may
|
||||
include erections or sexually charged content. These may appear on the Site
|
||||
Gallery as well as user profile pages.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<button type="submit" class="button is-primary">
|
||||
Save Website Preferences
|
||||
</button>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Account Settings -->
|
||||
<form method="POST" action="/settings">
|
||||
<input type="hidden" name="intent" value="settings">
|
||||
{{InputCSRF}}
|
||||
|
||||
<div class="card mb-5" id="account">
|
||||
<header class="card-header has-background-warning">
|
||||
<p class="card-header-title has-text-dark-dark">
|
||||
<i class="fa fa-gear pr-2"></i>
|
||||
Account Settings
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<div class="card-content">
|
||||
<div class="field">
|
||||
<label class="label" for="old_password">
|
||||
Current Password
|
||||
</label>
|
||||
<input type="password" class="input"
|
||||
name="old_password"
|
||||
id="old_password"
|
||||
placeholder="Current password"
|
||||
required>
|
||||
<p class="help">
|
||||
Enter your current password before making any changes to your
|
||||
email address or setting a new password.
|
||||
</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label" for="change_email">Change Email</label>
|
||||
<input type="email" class="input"
|
||||
id="change_email"
|
||||
name="change_email"
|
||||
placeholder="name@domain.com"
|
||||
value="{{.CurrentUser.Email}}">
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label">Change Password</label>
|
||||
<input type="password" class="input mb-2"
|
||||
name="new_password"
|
||||
placeholder="New password">
|
||||
<input type="password" class="input mb-2"
|
||||
name="new_password2"
|
||||
placeholder="Confirm new password">
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<button type="submit" class="button is-primary">
|
||||
Save Account Settings
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label" for="about_me">About Me</label>
|
||||
<textarea class="textarea" cols="60" rows="4"
|
||||
id="about_me"
|
||||
name="about_me"
|
||||
placeholder="A little blurb about myself">{{$User.GetProfileField "about_me"}}</textarea>
|
||||
<p class="help">
|
||||
Write a bit about yourself. <a href="/markdown" target="_blank">Markdown formatting</a> is supported here.
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Delete Account -->
|
||||
<div class="card mb-5" id="account">
|
||||
<header class="card-header has-background-danger">
|
||||
<p class="card-header-title has-text-light">
|
||||
<div class="field">
|
||||
<label class="label" for="interests">My Interests</label>
|
||||
<textarea class="textarea" cols="60" rows="4"
|
||||
id="interests"
|
||||
name="interests"
|
||||
placeholder="What kinds of things make you curious?">{{$User.GetProfileField "interests"}}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label" for="music_movies">Music/Bands/Movies</label>
|
||||
<textarea class="textarea" cols="60" rows="4"
|
||||
id="music_movies"
|
||||
name="music_movies"
|
||||
placeholder="What is your style of music or movie?">{{$User.GetProfileField "music_movies"}}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<button type="submit" class="button is-primary">
|
||||
Save Profile Settings
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Website Preferences -->
|
||||
<form method="POST" action="/settings">
|
||||
<input type="hidden" name="intent" value="preferences">
|
||||
{{InputCSRF}}
|
||||
|
||||
<div class="card mb-5" id="prefs">
|
||||
<header class="card-header has-background-success">
|
||||
<p class="card-header-title has-text-dark-dark">
|
||||
<i class="fa fa-square-check pr-2"></i>
|
||||
Website Preferences
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<div class="card-content">
|
||||
<div class="field">
|
||||
<label class="label">Profile Visibility</label>
|
||||
<label class="checkbox">
|
||||
<input type="radio"
|
||||
name="visibility"
|
||||
value="public"
|
||||
{{if eq .CurrentUser.Visibility "public"}}checked{{end}}>
|
||||
Public + Login Required
|
||||
<i class="fa fa-eye ml-2 has-text-info"></i>
|
||||
</label>
|
||||
<p class="help">
|
||||
The default is that users must be logged-in to even look at your profile
|
||||
page. If your profile URL (/u/{{.CurrentUser.Username}}) is visited by a
|
||||
logged-out browser, they are prompted to log in.
|
||||
</p>
|
||||
|
||||
<label class="checkbox mt-2">
|
||||
<input type="radio"
|
||||
name="visibility"
|
||||
value="external"
|
||||
{{if eq .CurrentUser.Visibility "external"}}checked{{end}}>
|
||||
Public + Limited Logged-out View
|
||||
<i class="fa fa-eye ml-2 has-text-danger"></i>
|
||||
</label>
|
||||
<p class="help">
|
||||
Your profile is fully visible to logged-in users, but if a logged-out browser
|
||||
visits your page they will see a very minimal view: only your profile picture
|
||||
and display name are shown.
|
||||
<a href="/u/{{.CurrentUser.Username}}?view=external" target="_blank">Preview <i class="fa fa-external-link"></i></a>
|
||||
</p>
|
||||
|
||||
<label class="checkbox mt-2">
|
||||
<input type="radio"
|
||||
name="visibility"
|
||||
value="private"
|
||||
{{if eq .CurrentUser.Visibility "private"}}checked{{end}}>
|
||||
Mark my profile page as "private"
|
||||
<i class="fa fa-lock ml-2 has-text-private"></i>
|
||||
</label>
|
||||
<p class="help">
|
||||
If you check this box then only friends who you have approved are able to
|
||||
see your profile page and gallery. Your gallery photos also will NOT appear
|
||||
on the Site Gallery page. If your profile page is visited by a logged-out
|
||||
viewer, they are prompted to log in.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="field">
|
||||
<label class="label">Explicit Content Filter</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox"
|
||||
name="explicit"
|
||||
value="true"
|
||||
{{if .CurrentUser.Explicit}}checked{{end}}>
|
||||
Show explicit content <i class="fa fa-fire has-text-danger ml-1"></i>
|
||||
</label>
|
||||
<p class="help">
|
||||
Check this box if you are OK seeing explicit content on this site, which may
|
||||
include erections or sexually charged content. These may appear on the Site
|
||||
Gallery as well as user profile pages.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="field">
|
||||
<label class="label mb-0">Who can send me the first <i class="fa fa-envelope"></i> Message?</label>
|
||||
|
||||
<div class="has-text-warning ml-4">
|
||||
<small><em>
|
||||
Note: this refers to Direct Messages on the main website
|
||||
(not inside the chat room).
|
||||
</em></small>
|
||||
{{.CurrentUser.GetProfileField "dm_privacy"}}
|
||||
</div>
|
||||
|
||||
<label class="checkbox">
|
||||
<input type="radio"
|
||||
name="dm_privacy"
|
||||
value=""
|
||||
{{if eq (.CurrentUser.GetProfileField "dm_privacy") ""}}checked{{end}}>
|
||||
Anybody on the site
|
||||
</label>
|
||||
<p class="help">
|
||||
Almost any member of the site may send you a Direct Message from your profile
|
||||
page (except for maybe <a href="/faq#shy-faqs" target="_blank">Shy Accounts</a>).
|
||||
</p>
|
||||
|
||||
<label class="checkbox">
|
||||
<input type="radio"
|
||||
name="dm_privacy"
|
||||
value="friends"
|
||||
{{if eq (.CurrentUser.GetProfileField "dm_privacy") "friends"}}checked{{end}}>
|
||||
Only people on my Friends list
|
||||
</label>
|
||||
<p class="help">
|
||||
Nobody can slide into your DMs except for friends (and admins if needed). Anybody
|
||||
may <em>reply</em> to messages that you send to them.
|
||||
</p>
|
||||
|
||||
<label class="checkbox">
|
||||
<input type="radio"
|
||||
name="dm_privacy"
|
||||
value="nobody"
|
||||
{{if eq (.CurrentUser.GetProfileField "dm_privacy") "nobody"}}checked{{end}}>
|
||||
Nobody (close my DMs)
|
||||
</label>
|
||||
<p class="help">
|
||||
Nobody can start a Direct Message conversation with you on the main website
|
||||
(except an admin if necessary). Anybody may <em>reply</em> to messages that you
|
||||
sent to them first.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- TODO: manually opt-in dark mode is hairy, look at
|
||||
those media queries in bulma-prefers-dark.js!
|
||||
<div class="field">
|
||||
<label class="label">Website Theme</label>
|
||||
<label class="checkbox">
|
||||
<input type="radio"
|
||||
name="theme"
|
||||
value=""
|
||||
{{if eq ($User.GetProfileField "theme") "" }}checked{{end}}>
|
||||
Automatic
|
||||
</label>
|
||||
<p class="help">
|
||||
Automatically chooses a theme based on your device settings.
|
||||
</p>
|
||||
|
||||
<label class="checkbox">
|
||||
<input type="radio"
|
||||
name="theme"
|
||||
value="light"
|
||||
{{if eq ($User.GetProfileField "theme") "light" }}checked{{end}}>
|
||||
Light
|
||||
</label>
|
||||
|
||||
<label class="checkbox">
|
||||
<input type="radio"
|
||||
name="theme"
|
||||
value="dark"
|
||||
{{if eq ($User.GetProfileField "theme") "dark" }}checked{{end}}>
|
||||
Dark
|
||||
</label>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<div class="field">
|
||||
<button type="submit" class="button is-primary">
|
||||
Save Website Preferences
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Account Settings -->
|
||||
<div id="account">
|
||||
<form method="POST" action="/settings">
|
||||
<input type="hidden" name="intent" value="settings">
|
||||
{{InputCSRF}}
|
||||
|
||||
<div class="card mb-5">
|
||||
<header class="card-header has-background-warning">
|
||||
<p class="card-header-title has-text-dark-dark">
|
||||
<i class="fa fa-gear pr-2"></i>
|
||||
Delete Account
|
||||
Account Settings
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<div class="card-content">
|
||||
<p class="block">
|
||||
If you would like to delete your account, please click
|
||||
on the button below.
|
||||
</p>
|
||||
<div class="field">
|
||||
<label class="label" for="old_password">
|
||||
Current Password
|
||||
</label>
|
||||
<input type="password" class="input"
|
||||
name="old_password"
|
||||
id="old_password"
|
||||
placeholder="Current password"
|
||||
required>
|
||||
<p class="help">
|
||||
Enter your current password before making any changes to your
|
||||
email address or setting a new password.
|
||||
</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label" for="change_email">Change Email</label>
|
||||
<input type="email" class="input"
|
||||
id="change_email"
|
||||
name="change_email"
|
||||
placeholder="name@domain.com"
|
||||
value="{{.CurrentUser.Email}}">
|
||||
</div>
|
||||
|
||||
<p class="block">
|
||||
<a href="/account/delete" class="button is-danger">
|
||||
Delete My Account
|
||||
</a>
|
||||
</p>
|
||||
<div class="field">
|
||||
<label class="label">Change Password</label>
|
||||
<input type="password" class="input mb-2"
|
||||
name="new_password"
|
||||
placeholder="New password">
|
||||
<input type="password" class="input mb-2"
|
||||
name="new_password2"
|
||||
placeholder="Confirm new password">
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<button type="submit" class="button is-primary">
|
||||
Save Account Settings
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Delete Account -->
|
||||
<div class="card mb-5">
|
||||
<header class="card-header has-background-danger">
|
||||
<p class="card-header-title has-text-light">
|
||||
<i class="fa fa-gear pr-2"></i>
|
||||
Delete Account
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<div class="card-content">
|
||||
<p class="block">
|
||||
If you would like to delete your account, please click
|
||||
on the button below.
|
||||
</p>
|
||||
|
||||
<p class="block">
|
||||
<a href="/account/delete" class="button is-danger">
|
||||
Delete My Account
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{define "scripts"}}
|
||||
<script>
|
||||
window.addEventListener("DOMContentLoaded", (event) => {
|
||||
// The tabs
|
||||
const $profile = document.querySelector("#profile"),
|
||||
$prefs = document.querySelector("#prefs"),
|
||||
$account = document.querySelector("#account")
|
||||
buttons = Array.from(document.getElementsByClassName("nonshy-tab-button"));
|
||||
|
||||
// Hide all by default.
|
||||
$profile.style.display = 'none';
|
||||
$prefs.style.display = 'none';
|
||||
$account.style.display = 'none';
|
||||
|
||||
// Current tab to select by default.
|
||||
let $activeTab = $profile;
|
||||
|
||||
// Global function to toggle the active tab.
|
||||
const showTab = (name) => {
|
||||
name = name.replace(/\.$/, '');
|
||||
if (!name) name = "profile";
|
||||
$activeTab.style.display = 'none';
|
||||
switch (name) {
|
||||
case "prefs":
|
||||
$activeTab = $prefs;
|
||||
break
|
||||
case "account":
|
||||
$activeTab = $account;
|
||||
break
|
||||
default:
|
||||
$activeTab = $profile;
|
||||
}
|
||||
|
||||
// Update the is-active classes on all the tabs.
|
||||
buttons.forEach(tab_ => {
|
||||
let name_ = tab_.href.split("#").pop(),
|
||||
parent = tab_.parentElement;
|
||||
|
||||
if (name !== name_) {
|
||||
console.log("button: remove is-active", tab_);
|
||||
parent.classList.remove("is-active");
|
||||
} else {
|
||||
console.log("button %s: ADD is-active", tab_);
|
||||
parent.classList.add("is-active");
|
||||
}
|
||||
});
|
||||
|
||||
$activeTab.style.display = 'block';
|
||||
history.replaceState(undefined, undefined, '#'+name);
|
||||
};
|
||||
|
||||
// Wire the tab buttons up.
|
||||
buttons.forEach(el => {
|
||||
let name = el.href.split("#").pop();
|
||||
el.addEventListener("click", (e) => {
|
||||
showTab(name);
|
||||
|
||||
e.preventDefault();
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
showTab(window.location.hash.replace(/^#/, ''));
|
||||
});
|
||||
</script>
|
||||
{{end}}
|
||||
|
|
|
@ -333,4 +333,4 @@
|
|||
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
Loading…
Reference in New Issue
Block a user