A clean, Markdown-based publishing platform made for writers. Write together, and build a community. https://writefreely.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

194 lines
5.9 KiB

  1. package writefreely
  2. import (
  3. "fmt"
  4. "github.com/gogits/gogs/pkg/tool"
  5. "github.com/gorilla/mux"
  6. "github.com/writeas/impart"
  7. "github.com/writeas/web-core/auth"
  8. "github.com/writeas/web-core/log"
  9. "github.com/writeas/writefreely/config"
  10. "net/http"
  11. "runtime"
  12. "strconv"
  13. "time"
  14. )
  15. var (
  16. appStartTime = time.Now()
  17. sysStatus systemStatus
  18. )
  19. type systemStatus struct {
  20. Uptime string
  21. NumGoroutine int
  22. // General statistics.
  23. MemAllocated string // bytes allocated and still in use
  24. MemTotal string // bytes allocated (even if freed)
  25. MemSys string // bytes obtained from system (sum of XxxSys below)
  26. Lookups uint64 // number of pointer lookups
  27. MemMallocs uint64 // number of mallocs
  28. MemFrees uint64 // number of frees
  29. // Main allocation heap statistics.
  30. HeapAlloc string // bytes allocated and still in use
  31. HeapSys string // bytes obtained from system
  32. HeapIdle string // bytes in idle spans
  33. HeapInuse string // bytes in non-idle span
  34. HeapReleased string // bytes released to the OS
  35. HeapObjects uint64 // total number of allocated objects
  36. // Low-level fixed-size structure allocator statistics.
  37. // Inuse is bytes used now.
  38. // Sys is bytes obtained from system.
  39. StackInuse string // bootstrap stacks
  40. StackSys string
  41. MSpanInuse string // mspan structures
  42. MSpanSys string
  43. MCacheInuse string // mcache structures
  44. MCacheSys string
  45. BuckHashSys string // profiling bucket hash table
  46. GCSys string // GC metadata
  47. OtherSys string // other system allocations
  48. // Garbage collector statistics.
  49. NextGC string // next run in HeapAlloc time (bytes)
  50. LastGC string // last run in absolute time (ns)
  51. PauseTotalNs string
  52. PauseNs string // circular buffer of recent GC pause times, most recent at [(NumGC+255)%256]
  53. NumGC uint32
  54. }
  55. func handleViewAdminDash(app *app, u *User, w http.ResponseWriter, r *http.Request) error {
  56. updateAppStats()
  57. p := struct {
  58. *UserPage
  59. SysStatus systemStatus
  60. Config config.AppCfg
  61. Message, ConfigMessage string
  62. AboutPage, PrivacyPage string
  63. }{
  64. UserPage: NewUserPage(app, r, u, "Admin", nil),
  65. SysStatus: sysStatus,
  66. Config: app.cfg.App,
  67. Message: r.FormValue("m"),
  68. ConfigMessage: r.FormValue("cm"),
  69. }
  70. var err error
  71. p.AboutPage, err = getAboutPage(app)
  72. if err != nil {
  73. return err
  74. }
  75. p.PrivacyPage, _, err = getPrivacyPage(app)
  76. if err != nil {
  77. return err
  78. }
  79. showUserPage(w, "admin", p)
  80. return nil
  81. }
  82. func handleAdminUpdateSite(app *app, u *User, w http.ResponseWriter, r *http.Request) error {
  83. vars := mux.Vars(r)
  84. id := vars["page"]
  85. // Validate
  86. if id != "about" && id != "privacy" {
  87. return impart.HTTPError{http.StatusNotFound, "No such page."}
  88. }
  89. // Update page
  90. m := ""
  91. err := app.db.UpdateDynamicContent(id, r.FormValue("content"))
  92. if err != nil {
  93. m = "?m=" + err.Error()
  94. }
  95. return impart.HTTPError{http.StatusFound, "/admin" + m + "#page-" + id}
  96. }
  97. func handleAdminUpdateConfig(app *app, u *User, w http.ResponseWriter, r *http.Request) error {
  98. app.cfg.App.SiteName = r.FormValue("site_name")
  99. app.cfg.App.SiteDesc = r.FormValue("site_desc")
  100. app.cfg.App.OpenRegistration = r.FormValue("open_registration") == "on"
  101. mul, err := strconv.Atoi(r.FormValue("min_username_len"))
  102. if err == nil {
  103. app.cfg.App.MinUsernameLen = mul
  104. }
  105. mb, err := strconv.Atoi(r.FormValue("max_blogs"))
  106. if err == nil {
  107. app.cfg.App.MaxBlogs = mb
  108. }
  109. app.cfg.App.Federation = r.FormValue("federation") == "on"
  110. app.cfg.App.PublicStats = r.FormValue("public_stats") == "on"
  111. app.cfg.App.Private = r.FormValue("private") == "on"
  112. app.cfg.App.LocalTimeline = r.FormValue("local_timeline") == "on"
  113. if app.cfg.App.LocalTimeline && app.timeline == nil {
  114. log.Info("Initializing local timeline...")
  115. initLocalTimeline(app)
  116. }
  117. m := "?cm=Configuration+saved."
  118. err = config.Save(app.cfg, app.cfgFile)
  119. if err != nil {
  120. m = "?cm=" + err.Error()
  121. }
  122. return impart.HTTPError{http.StatusFound, "/admin" + m + "#config"}
  123. }
  124. func updateAppStats() {
  125. sysStatus.Uptime = tool.TimeSincePro(appStartTime)
  126. m := new(runtime.MemStats)
  127. runtime.ReadMemStats(m)
  128. sysStatus.NumGoroutine = runtime.NumGoroutine()
  129. sysStatus.MemAllocated = tool.FileSize(int64(m.Alloc))
  130. sysStatus.MemTotal = tool.FileSize(int64(m.TotalAlloc))
  131. sysStatus.MemSys = tool.FileSize(int64(m.Sys))
  132. sysStatus.Lookups = m.Lookups
  133. sysStatus.MemMallocs = m.Mallocs
  134. sysStatus.MemFrees = m.Frees
  135. sysStatus.HeapAlloc = tool.FileSize(int64(m.HeapAlloc))
  136. sysStatus.HeapSys = tool.FileSize(int64(m.HeapSys))
  137. sysStatus.HeapIdle = tool.FileSize(int64(m.HeapIdle))
  138. sysStatus.HeapInuse = tool.FileSize(int64(m.HeapInuse))
  139. sysStatus.HeapReleased = tool.FileSize(int64(m.HeapReleased))
  140. sysStatus.HeapObjects = m.HeapObjects
  141. sysStatus.StackInuse = tool.FileSize(int64(m.StackInuse))
  142. sysStatus.StackSys = tool.FileSize(int64(m.StackSys))
  143. sysStatus.MSpanInuse = tool.FileSize(int64(m.MSpanInuse))
  144. sysStatus.MSpanSys = tool.FileSize(int64(m.MSpanSys))
  145. sysStatus.MCacheInuse = tool.FileSize(int64(m.MCacheInuse))
  146. sysStatus.MCacheSys = tool.FileSize(int64(m.MCacheSys))
  147. sysStatus.BuckHashSys = tool.FileSize(int64(m.BuckHashSys))
  148. sysStatus.GCSys = tool.FileSize(int64(m.GCSys))
  149. sysStatus.OtherSys = tool.FileSize(int64(m.OtherSys))
  150. sysStatus.NextGC = tool.FileSize(int64(m.NextGC))
  151. sysStatus.LastGC = fmt.Sprintf("%.1fs", float64(time.Now().UnixNano()-int64(m.LastGC))/1000/1000/1000)
  152. sysStatus.PauseTotalNs = fmt.Sprintf("%.1fs", float64(m.PauseTotalNs)/1000/1000/1000)
  153. sysStatus.PauseNs = fmt.Sprintf("%.3fs", float64(m.PauseNs[(m.NumGC+255)%256])/1000/1000/1000)
  154. sysStatus.NumGC = m.NumGC
  155. }
  156. func adminResetPassword(app *app, u *User, newPass string) error {
  157. hashedPass, err := auth.HashPass([]byte(newPass))
  158. if err != nil {
  159. return impart.HTTPError{http.StatusInternalServerError, fmt.Sprintf("Could not create password hash: %v", err)}
  160. }
  161. err = app.db.ChangePassphrase(u.ID, true, "", hashedPass)
  162. if err != nil {
  163. return impart.HTTPError{http.StatusInternalServerError, fmt.Sprintf("Could not update passphrase: %v", err)}
  164. }
  165. return nil
  166. }