Page MenuHomeMusing Studio

No OneTemporary

diff --git a/templates/user/admin/users.tmpl b/templates/user/admin/users.tmpl
index 6d5d6f7..03a3f6c 100644
--- a/templates/user/admin/users.tmpl
+++ b/templates/user/admin/users.tmpl
@@ -1,36 +1,35 @@
{{define "users"}}
{{template "header" .}}
<div class="snug content-container">
{{template "admin-header" .}}
<h2 id="posts-header" style="display: flex; justify-content: space-between;">Users <span style="font-style: italic; font-size: 0.75em;">{{.TotalUsers}} total</strong></h2>
<table class="classy export" style="width:100%">
<tr>
<th>User</th>
<th>Joined</th>
<th>Type</th>
<th>Status</th>
</tr>
{{range .Users}}
<tr>
<td><a href="/admin/user/{{.Username}}">{{.Username}}</a></td>
<td>{{.CreatedFriendly}}</td>
<td style="text-align:center">{{if .IsAdmin}}Admin{{else}}User{{end}}</td>
<td style="text-align:center">
- <a
- href="/admin/user/{{.Username}}#status"
- title="View or change account status">{{if eq .Status 1}}suspended{{else}}active{{end}}</a></td>
+ <a href="/admin/user/{{.Username}}#status" title="View or change account status">{{if .IsSuspended}}suspended{{else}}active{{end}}</a>
+ </td>
</tr>
{{end}}
</table>
<nav class="pager">
{{range $n := .TotalPages}}<a href="/admin/users{{if ne $n 1}}?p={{$n}}{{end}}" {{if eq $.CurPage $n}}class="selected"{{end}}>{{$n}}</a>{{end}}
</nav>
</div>
{{template "footer" .}}
{{end}}
diff --git a/templates/user/admin/view-user.tmpl b/templates/user/admin/view-user.tmpl
index 01eb1f0..9226c39 100644
--- a/templates/user/admin/view-user.tmpl
+++ b/templates/user/admin/view-user.tmpl
@@ -1,119 +1,120 @@
{{define "view-user"}}
{{template "header" .}}
<style>
table.classy th {
text-align: left;
}
h3 {
font-weight: normal;
}
td.active-suspend {
display: flex;
align-items: center;
}
td.active-suspend > input[type="submit"] {
margin-left: auto;
margin-right: 5%;
}
@media only screen and (max-width: 500px) {
td.active-suspend {
flex-wrap: wrap;
}
td.active-suspend > input[type="submit"] {
margin: auto;
}
}
</style>
<div class="snug content-container">
{{template "admin-header" .}}
<h2 id="posts-header">{{.User.Username}}</h2>
<table class="classy export">
<tr>
<th>No.</th>
<td>{{.User.ID}}</td>
</tr>
<tr>
<th>Type</th>
<td>{{if .User.IsAdmin}}Admin{{else}}User{{end}}</td>
</tr>
<tr>
<th>Username</th>
<td>{{.User.Username}}</td>
</tr>
<tr>
<th>Joined</th>
<td>{{.User.CreatedFriendly}}</td>
</tr>
<tr>
<th>Total Posts</th>
<td>{{.TotalPosts}}</td>
</tr>
<tr>
<th>Last Post</th>
<td>{{if .LastPost}}{{.LastPost}}{{else}}Never{{end}}</td>
</tr>
<tr>
<form action="/admin/user/{{.User.Username}}/status" method="POST">
<a id="status"/>
<th>Status</th>
- {{if eq .User.Status 1}}
- <td class="active-suspend"><p>User is currently Suspended</p><input type="submit" value="Activate"/></td>
- {{else}}
<td class="active-suspend">
- <p>User is currently Active</p>
+ {{if .User.IsSuspended}}
+ <p>Suspended</p>
+ <input type="submit" value="Activate"/>
+ {{else}}
+ <p>Active</p>
<input class="danger" type="submit" value="Suspend" {{if .User.IsAdmin}}disabled{{end}}/>
- </td>
{{end}}
+ </td>
</form>
</tr>
</table>
<h2>Blogs</h2>
{{range .Colls}}
<h3><a href="/{{.Alias}}/">{{.Title}}</a></h3>
<table class="classy export">
<tr>
<th>Alias</th>
<td>{{.Alias}}</td>
</tr>
<tr>
<th>Title</th>
<td>{{.Title}}</td>
</tr>
<tr>
<th>Description</th>
<td>{{.Description}}</td>
</tr>
<tr>
<th>Visibility</th>
<td>{{.FriendlyVisibility}}</td>
</tr>
<tr>
<th>Views</th>
<td>{{.Views}}</td>
</tr>
<tr>
<th>Posts</th>
<td>{{.TotalPosts}}</td>
</tr>
<tr>
<th>Last Post</th>
<td>{{if .LastPost}}{{.LastPost}}{{else}}Never{{end}}</td>
</tr>
{{if $.Config.Federation}}
<tr>
<th>Fediverse Followers</th>
<td>{{.Followers}}</td>
</tr>
{{end}}
</table>
{{end}}
</div>
{{template "footer" .}}
{{end}}
diff --git a/users.go b/users.go
index 05b5bb4..5eb2e61 100644
--- a/users.go
+++ b/users.go
@@ -1,128 +1,132 @@
/*
* Copyright © 2018 A Bunch Tell LLC.
*
* This file is part of WriteFreely.
*
* WriteFreely is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, included
* in the LICENSE file in this source code package.
*/
package writefreely
import (
"time"
"github.com/guregu/null/zero"
"github.com/writeas/web-core/data"
"github.com/writeas/web-core/log"
"github.com/writeas/writefreely/key"
)
type UserStatus int
const (
UserActive = iota
UserSuspended
)
type (
userCredentials struct {
Alias string `json:"alias" schema:"alias"`
Pass string `json:"pass" schema:"pass"`
Email string `json:"email" schema:"email"`
Web bool `json:"web" schema:"-"`
To string `json:"-" schema:"to"`
EmailLogin bool `json:"via_email" schema:"via_email"`
}
userRegistration struct {
userCredentials
InviteCode string `json:"invite_code" schema:"invite_code"`
Honeypot string `json:"fullname" schema:"fullname"`
Normalize bool `json:"normalize" schema:"normalize"`
Signup bool `json:"signup" schema:"signup"`
}
// AuthUser contains information for a newly authenticated user (either
// from signing up or logging in).
AuthUser struct {
AccessToken string `json:"access_token,omitempty"`
Password string `json:"password,omitempty"`
User *User `json:"user"`
// Verbose user data
Posts *[]PublicPost `json:"posts,omitempty"`
Collections *[]Collection `json:"collections,omitempty"`
}
// User is a consistent user object in the database and all contexts (auth
// and non-auth) in the API.
User struct {
ID int64 `json:"-"`
Username string `json:"username"`
HashedPass []byte `json:"-"`
HasPass bool `json:"has_pass"`
Email zero.String `json:"email"`
Created time.Time `json:"created"`
Status UserStatus `json:"status"`
clearEmail string `json:"email"`
}
userMeStats struct {
TotalCollections, TotalArticles, CollectionPosts uint64
}
ExportUser struct {
*User
Collections *[]CollectionObj `json:"collections"`
AnonymousPosts []PublicPost `json:"posts"`
}
PublicUser struct {
Username string `json:"username"`
}
)
// EmailClear decrypts and returns the user's email, caching it in the user
// object.
func (u *User) EmailClear(keys *key.Keychain) string {
if u.clearEmail != "" {
return u.clearEmail
}
if u.Email.Valid && u.Email.String != "" {
email, err := data.Decrypt(keys.EmailKey, []byte(u.Email.String))
if err != nil {
log.Error("Error decrypting user email: %v", err)
} else {
u.clearEmail = string(email)
return u.clearEmail
}
}
return ""
}
func (u User) CreatedFriendly() string {
/*
// TODO: accept a locale in this method and use that for the format
var loc monday.Locale = monday.LocaleEnUS
return monday.Format(u.Created, monday.DateTimeFormatsByLocale[loc], loc)
*/
return u.Created.Format("January 2, 2006, 3:04 PM")
}
// Cookie strips down an AuthUser to contain only information necessary for
// cookies.
func (u User) Cookie() *User {
u.HashedPass = []byte{}
return &u
}
func (u *User) IsAdmin() bool {
// TODO: get this from database
return u.ID == 1
}
+
+func (u *User) IsSuspended() bool {
+ return u.Status&UserSuspended != 0
+}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Apr 27, 9:23 AM (10 m, 26 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3216560

Event Timeline