stations.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. import { Elysia } from 'elysia'
  2. import { Eta } from "eta"
  3. const eta = new Eta({ views: "./templates" })
  4. import Auth from '../../../utils/auth';
  5. import Meteostanice from '../../../utils/meteostanice';
  6. import validateTurnstile from '../../../utils/validateTurnstile';
  7. import normalizeEmail from '../../../utils/normalizeEmail';
  8. import stationsHistory from './stationsHistory';
  9. export default (langName, lang) => new Elysia({ prefix: "/stations" })
  10. .use(stationsHistory(langName, lang))
  11. .get("/", async ({ cookie, redirect, set }) => {
  12. const token = cookie.session.value
  13. const session = await Auth.getSession(token)
  14. if (!session) {
  15. return redirect(`/${langName === "sk" ? `` : `${langName}/`}auth?error=loginNeeded`)
  16. }
  17. const user = Auth.getUser(session.email)
  18. const meteostanice = Meteostanice.getOwned(session.email)
  19. set.headers['content-type'] = 'text/html; charset=utf8'
  20. return eta.render(`${langName}/panel/stations/index`, { user, meteostanice })
  21. })
  22. .get("/add", async ({ cookie, redirect, set }) => {
  23. const token = cookie.session.value
  24. const session = await Auth.getSession(token)
  25. if (!session) {
  26. return redirect(`/${langName === "sk" ? `` : `${langName}/`}auth?error=loginNeeded`)
  27. }
  28. const user = Auth.getUser(session.email)
  29. set.headers['content-type'] = 'text/html; charset=utf8'
  30. return eta.render(`${langName}/panel/stations/add`, { siteKey: process.env.TURNSTILE_SITE_KEY, user })
  31. })
  32. .post("/add", async ({ request, server, cookie, redirect, body, set }) => {
  33. const clientIP = request.headers.get('x-forwarded-for') ?? server.requestIP(request).address
  34. const token = cookie.session.value
  35. const session = await Auth.getSession(token)
  36. if (!session) {
  37. return redirect(`/${langName === "sk" ? `` : `${langName}/`}auth?error=loginNeeded`)
  38. }
  39. const user = Auth.getUser(session.email)
  40. const turnstileResponse = body?.["cf-turnstile-response"]
  41. if (!turnstileResponse) {
  42. set.headers['content-type'] = 'text/html; charset=utf8'
  43. return eta.render(`${langName}/panel/stations/add`, { siteKey: process.env.TURNSTILE_SITE_KEY, lang, user, error: "turnstile.noToken" })
  44. }
  45. const turnstileValid = await validateTurnstile(turnstileResponse, clientIP)
  46. if (!turnstileValid.success) {
  47. let errorMessage = `turnstile.unavailable`;
  48. if (turnstileValid["error-codes"]?.includes("invalid-input-response"))
  49. errorMessage = `turnstile.invalidResponse`
  50. if (turnstileValid["error-codes"]?.includes("timeout-or-duplicate"))
  51. errorMessage = `turnstile.keyUsedOrExpired`
  52. set.headers['content-type'] = 'text/html; charset=utf8'
  53. return eta.render(`${langName}/panel/stations/add`, { siteKey: process.env.TURNSTILE_SITE_KEY, lang, user, error: errorMessage })
  54. }
  55. let name = body?.name
  56. if (!name) name = lang.general.generateName()
  57. const description = body?.description
  58. Meteostanice.add(session.email, name, description)
  59. return redirect(`/${langName === "sk" ? `` : `${langName}/`}panel/stations`)
  60. })
  61. .get("/:station", async ({ cookie, redirect, set, params: { station } }) => {
  62. const token = cookie.session.value
  63. const session = await Auth.getSession(token)
  64. if (!session) {
  65. return redirect(`/${langName === "sk" ? `` : `${langName}/`}auth?error=loginNeeded`)
  66. }
  67. const user = Auth.getUser(session.email)
  68. if (!station) {
  69. set.headers['content-type'] = 'text/html; charset=utf8'
  70. return eta.render(`${langName}/panel/stations/notFound`, { lang, user })
  71. }
  72. const meteostanica = Meteostanice.get(session.email, station)
  73. if (!meteostanica) {
  74. set.headers['content-type'] = 'text/html; charset=utf8'
  75. return eta.render(`${langName}/panel/stations/notFound`, { lang, user })
  76. }
  77. const data = Meteostanice.getData(meteostanica.id)
  78. set.headers['content-type'] = 'text/html; charset=utf8'
  79. return eta.render(`${langName}/panel/stations/station`, { user, meteostanica, data })
  80. })
  81. .get("/:station/edit", async ({ cookie, redirect, set, params: { station } }) => {
  82. const token = cookie.session.value
  83. const session = await Auth.getSession(token)
  84. if (!session) {
  85. return redirect(`/${langName === "sk" ? `` : `${langName}/`}auth?error=loginNeeded`)
  86. }
  87. const user = Auth.getUser(session.email)
  88. if (!station) {
  89. set.headers['content-type'] = 'text/html; charset=utf8'
  90. return eta.render(`${langName}/panel/stations/notFound`, { lang, user })
  91. }
  92. const meteostanica = Meteostanice.get(session.email, station)
  93. if (!meteostanica) {
  94. set.headers['content-type'] = 'text/html; charset=utf8'
  95. return eta.render(`${langName}/panel/stations/notFound`, { lang, user })
  96. }
  97. set.headers['content-type'] = 'text/html; charset=utf8'
  98. return eta.render(`${langName}/panel/stations/edit`, { siteKey: process.env.TURNSTILE_SITE_KEY, user, meteostanica })
  99. })
  100. .post("/:station/edit", async ({ request, server, cookie, redirect, params: { station }, body, set }) => {
  101. const clientIP = request.headers.get('x-forwarded-for') ?? server.requestIP(request).address
  102. const token = cookie.session.value
  103. const session = await Auth.getSession(token)
  104. if (!session) {
  105. return redirect(`/${langName === "sk" ? `` : `${langName}/`}auth?error=loginNeeded`)
  106. }
  107. const user = Auth.getUser(session.email)
  108. if (!station) {
  109. set.headers['content-type'] = 'text/html; charset=utf8'
  110. return eta.render(`${langName}/panel/stations/notFound`, { lang, user })
  111. }
  112. const meteostanica = Meteostanice.get(session.email, station)
  113. if (!meteostanica) {
  114. set.headers['content-type'] = 'text/html; charset=utf8'
  115. return eta.render(`${langName}/panel/stations/notFound`, { lang, user })
  116. }
  117. const turnstileResponse = body?.["cf-turnstile-response"]
  118. if (!turnstileResponse) {
  119. set.headers['content-type'] = 'text/html; charset=utf8'
  120. return eta.render(`${langName}/panel/stations/edit`, { siteKey: process.env.TURNSTILE_SITE_KEY, lang, user, meteostanica, error: "turnstile.noToken" })
  121. }
  122. const turnstileValid = await validateTurnstile(turnstileResponse, clientIP)
  123. if (!turnstileValid.success) {
  124. let errorMessage = `turnstile.unavailable`;
  125. if (turnstileValid["error-codes"]?.includes("invalid-input-response"))
  126. errorMessage = `turnstile.invalidResponse`
  127. if (turnstileValid["error-codes"]?.includes("timeout-or-duplicate"))
  128. errorMessage = `turnstile.keyUsedOrExpired`
  129. set.headers['content-type'] = 'text/html; charset=utf8'
  130. return eta.render(`${langName}/panel/stations/edit`, { siteKey: process.env.TURNSTILE_SITE_KEY, lang, user, meteostanica, error: errorMessage })
  131. }
  132. const newName = body?.name
  133. if (!newName) {
  134. set.headers['content-type'] = 'text/html; charset=utf8'
  135. return eta.render(`${langName}/panel/stations/edit`, { siteKey: process.env.TURNSTILE_SITE_KEY, lang, user, meteostanica, error: "noName" })
  136. }
  137. const newOwnerEmail = body?.owner
  138. if (!normalizeEmail(newOwnerEmail)) {
  139. set.headers['content-type'] = 'text/html; charset=utf8'
  140. return eta.render(`${langName}/panel/stations/edit`, { siteKey: process.env.TURNSTILE_SITE_KEY, lang, user, meteostanica, error: "invalidOwner" })
  141. }
  142. const newOwner = Auth.getUser(newOwnerEmail)
  143. if (!newOwner) {
  144. set.headers['content-type'] = 'text/html; charset=utf8'
  145. return eta.render(`${langName}/panel/stations/edit`, { siteKey: process.env.TURNSTILE_SITE_KEY, lang, user, meteostanica, error: "ownerUserNotFound", errorDetails: { newOwnerEmail } })
  146. }
  147. const newDescription = body?.description
  148. Meteostanice.edit(meteostanica.id, newName, newDescription, newOwnerEmail)
  149. return redirect(`/${langName === "sk" ? `` : `${langName}/`}panel/stations/${meteostanica.id}`)
  150. })
  151. .get("/:station/resetWebsocketKey", async ({ cookie, redirect, set, params: { station } }) => {
  152. const token = cookie.session.value
  153. const session = await Auth.getSession(token)
  154. if (!session) {
  155. return redirect(`/${langName === "sk" ? `` : `${langName}/`}auth?error=loginNeeded`)
  156. }
  157. const user = Auth.getUser(session.email)
  158. if (!station) {
  159. set.headers['content-type'] = 'text/html; charset=utf8'
  160. return eta.render(`${langName}/panel/stations/notFound`, { lang, user })
  161. }
  162. const meteostanica = Meteostanice.get(session.email, station)
  163. if (!meteostanica) {
  164. set.headers['content-type'] = 'text/html; charset=utf8'
  165. return eta.render(`${langName}/panel/stations/notFound`, { lang, user })
  166. }
  167. Meteostanice.resetWebsocketKey(meteostanica.id)
  168. return redirect(`/${langName === "sk" ? `` : `${langName}/`}panel/stations/${meteostanica.id}`)
  169. })
  170. .get("/:station/delete", async ({ cookie, redirect, set, params: { station } }) => {
  171. const token = cookie.session.value
  172. const session = await Auth.getSession(token)
  173. if (!session) {
  174. return redirect(`/${langName === "sk" ? `` : `${langName}/`}auth?error=loginNeeded`)
  175. }
  176. const user = Auth.getUser(session.email)
  177. if (!station) {
  178. set.headers['content-type'] = 'text/html; charset=utf8'
  179. return eta.render(`${langName}/panel/stations/notFound`, { lang, user })
  180. }
  181. const meteostanica = Meteostanice.get(session.email, station)
  182. if (!meteostanica) {
  183. set.headers['content-type'] = 'text/html; charset=utf8'
  184. return eta.render(`${langName}/panel/stations/notFound`, { lang, user })
  185. }
  186. set.headers['content-type'] = 'text/html; charset=utf8'
  187. return eta.render(`${langName}/panel/stations/delete`, { user, meteostanica })
  188. })
  189. .get("/:station/deleteConfirm", async ({ cookie, redirect, set, params: { station } }) => {
  190. const token = cookie.session.value
  191. const session = await Auth.getSession(token)
  192. if (!session) {
  193. return redirect(`/${langName === "sk" ? `` : `${langName}/`}auth?error=loginNeeded`)
  194. }
  195. const user = Auth.getUser(session.email)
  196. if (!station) {
  197. set.headers['content-type'] = 'text/html; charset=utf8'
  198. return eta.render(`${langName}/panel/stations/notFound`, { siteKey: process.env.TURNSTILE_SITE_KEY, lang, user })
  199. }
  200. const meteostanica = Meteostanice.get(session.email, station)
  201. if (!meteostanica) {
  202. set.headers['content-type'] = 'text/html; charset=utf8'
  203. return eta.render(`${langName}/panel/stations/notFound`, { siteKey: process.env.TURNSTILE_SITE_KEY, lang, user })
  204. }
  205. Meteostanice.delete(meteostanica.id)
  206. return redirect(`/${langName === "sk" ? `` : `${langName}/`}panel/stations`)
  207. })
  208. .get('/:station/currentData', async ({ cookie, redirect, set, params: { station } }) => {
  209. const token = cookie.session.value
  210. const session = await Auth.getSession(token)
  211. if (!session) {
  212. return redirect(`/${langName === "sk" ? `` : `${langName}/`}auth?error=loginNeeded`)
  213. }
  214. const user = Auth.getUser(session.email)
  215. if (!station) {
  216. set.headers['content-type'] = 'text/html; charset=utf8'
  217. return eta.render(`${langName}/panel/stations/notFound`, { siteKey: process.env.TURNSTILE_SITE_KEY, lang, user })
  218. }
  219. const meteostanica = Meteostanice.get(session.email, station)
  220. if (!meteostanica) {
  221. set.headers['content-type'] = 'text/html; charset=utf8'
  222. return eta.render(`${langName}/panel/stations/notFound`, { siteKey: process.env.TURNSTILE_SITE_KEY, lang, user })
  223. }
  224. const data = Meteostanice.getData(station)
  225. return data?.[0]
  226. })