Skip to content

Commit

Permalink
Merge pull request #381 from HapticX/dev
Browse files Browse the repository at this point in the history
New builtin decorators
  • Loading branch information
Ethosa authored Dec 10, 2024
2 parents 60093e9 + 420599f commit 5476224
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 17 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ jobs:
- name: Install Dependencies 🔃
run: |
nimble refresh
nimble install -y -d
nimble install checksums -y
nimble install regex -y
nimble install -y -d
# - uses: reviewdog/action-nimlint@v1
# with:
# github_token: ${{ secrets.github_token }}
Expand All @@ -87,6 +87,7 @@ jobs:
- name: Build C tests (Default HTTP Server) ⚡
run: |
export PATH=$PATH:$PWD/.nim_runtime/bin
nimble install jwt -y
cd tests
echo "###===--- Default for" $file "---===###"
for file in $(ls -v testc*.nim); do
Expand Down Expand Up @@ -115,6 +116,7 @@ jobs:
- name: Build C tests (Default HTTP Server) ⚡
run: |
export PATH=$PATH:$PWD/.nim_runtime/bin
nimble install jwt -y
cd tests
echo "###===--- Default for" $file "---===###"
for file in $(ls -v testc*.nim); do
Expand Down Expand Up @@ -143,6 +145,7 @@ jobs:
- name: Build C tests (MicroAsyncHttpServer) ⚡
run: |
export PATH=$PATH:$PWD/.nim_runtime/bin
nimble install jwt -y
cd tests
for file in $(ls -v testc*.nim); do
echo "###===--- C Test for " $file " via MicroAsyncHttpServer ---===###"
Expand Down Expand Up @@ -170,6 +173,7 @@ jobs:
- name: Build C tests (HttpX HTTP Server) ⚡
run: |
export PATH=$PATH:$PWD/.nim_runtime/bin
nimble install jwt -y
cd tests
for file in $(ls -v testc*.nim); do
echo "###===--- C Test for " $file " via Httpx ---===###"
Expand Down Expand Up @@ -197,6 +201,7 @@ jobs:
- name: Build C tests (HttpBeast HTTP Server) ⚡
run: |
export PATH=$PATH:$PWD/.nim_runtime/bin
nimble install jwt -y
cd tests
for file in $(ls -v testc*.nim); do
echo "###===--- C Test for " $file " via HttpBeast ---===###"
Expand Down
32 changes: 24 additions & 8 deletions examples/website/src/docs/decorators.nim
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,36 @@ import
proc Decorators*(): TagRef =
buildHtml:
tDiv(class = "flex flex-col px-8 py-2 xl:h-fit gap-4"):
tH1: {translate"Route Decorators 🔌"}
tH1: { translate"Route Decorators 🔌" }

tP: {translate"HappyX (at Nim side) provides efficient compile-time route decorators."}
tP: {translate"Route decorators is little 'middleware', that edits route code at compile-time"}
tP: { translate"HappyX (at Nim side) provides efficient compile-time route decorators." }
tP: { translate"Route decorators is little 'middleware', that edits route code at compile-time" }

tH2: {translate"Usage 🤔"}
tP: {translate"Here you can see simple decorator usage"}
tH2: { translate"Usage 🤔" }
tP: { translate"Here you can see simple decorator usage" }

CodeBlock("nim", nimSsrRouteDecorator, "route_decorator")

tH2: {translate"Custom Decorators 💡"}
tP: {translate"You can create your own decorators also:"}
tH2: { translate"Decorators out of the box 📦" }
tP: { translate"Basic Auth looks like this:" }

CodeBlock("nim", nimAuthBasic, "auth_basic")

tP: { translate"Authorization: JWT TOKEN and Authorization: Bearer JWT TOKEN look like this:" }

CodeBlock("nim", nimAuthJWT, "auth_jwt")
CodeBlock("nim", nimAuthBearerJWT, "auth_bearer_jwt")

Tip:
tDiv(class = "flex gap-2"):
tP: { translate"To use JWT, you need to install the library" }
tA(href = "https://github.com/yglukhov/nim-jwt", target = "_blank"):
"yglukhov/nim-jwt"

tH2: { translate"Custom Decorators 💡"}
tP: { translate"You can create your own decorators also:" }

CodeBlock("nim", nimAssignRouteDecorator, "route_decorator")

Tip:
tP: {translate"You can use route decorators in SSR, SSG, and SPA project types with Nim."}
tP: { translate"You can use route decorators in SSR, SSG, and SPA project types with Nim." }
23 changes: 23 additions & 0 deletions examples/website/src/ui/code/nim_ssr.nim
Original file line number Diff line number Diff line change
Expand Up @@ -647,4 +647,27 @@ serve "127.0.0.1", 5123:
# used in other cases of websocket errors
wsError:
echo "unknown WS error"
"""
nimAuthBasic* = """serve ... :
@AuthBasic
get "/test/basic-auth":
echo username # from @AuthBasic
echo password # from @AuthBasic
return "Hello, {username}!"
"""
nimAuthJWT* = """serve ... :
# Authorization: JWT_TOKEN
@AuthJWT(token)
post "/test/jwt":
if token.hasKey("name"):
return "Hello, " & token["name"].node.str
return "who are you???"
"""
nimAuthBearerJWT* = """serve ... :
# Authorization: Bearer JWT_TOKEN
@AuthBearerJWT(token)
post "/test/jwt":
if token.hasKey("name"):
return "Hello, " & token["name"].node.str
return "who are you???"
"""
24 changes: 24 additions & 0 deletions examples/website/src/ui/translations.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2672,6 +2672,30 @@ translatable:
"zh" -> "除了上述使用的路由外,Websockets还具有其他路由。以下是所有路由的完整列表:"
"fr" -> "En plus des routes utilisées ci-dessus, les websockets ont d'autres routes. Voici la liste complète de toutes les routes :"
"ko" -> "위에서 사용한 경로 외에도 웹소켓에는 다른 경로가 있습니다. 모든 경로의 전체 목록은 다음과 같습니다:"
"Decorators out of the box 📦":
"ru" -> "Декораторы из коробки 📦"
"ja" -> "すぐに使えるデコレーター 📦"
"zh" -> "开箱即用的装饰器 📦"
"fr" -> "Décorateurs prêts à l'emploi 📦"
"ko" -> "바로 사용할 수 있는 데코레이터 📦"
"Basic Auth looks like this:":
"ru" -> "Basic Auth выглядит следующим образом:"
"ja" -> "Basic認証は次のようになります:"
"zh" -> "Basic Auth 看起来如下:"
"fr" -> "L'authentification de base ressemble à ceci :"
"ko" -> "Basic Auth는 다음과 같이 보입니다:"
"Authorization: JWT TOKEN and Authorization: Bearer JWT TOKEN look like this:":
"ru" -> "Authorization: JWT TOKEN и Authorization: Bearer JWT TOKEN выглядят следующим образом:"
"ja" -> "Authorization: JWT TOKENおよびAuthorization: Bearer JWT TOKENは次のようになります:"
"zh" -> "Authorization: JWT TOKEN 和 Authorization: Bearer JWT TOKEN 如下所示:"
"fr" -> "Authorization: JWT TOKEN et Authorization: Bearer JWT TOKEN ressemblent à ceci :"
"ko" -> "Authorization: JWT TOKEN 및 Authorization: Bearer JWT TOKEN은 다음과 같이 보입니다:"
"To use JWT, you need to install the library":
"ru" -> "Для использования JWT необходимо установить библиотеку"
"ja" -> "JWTを使用するには、ライブラリをインストールする必要があります"
"zh" -> "要使用JWT,您需要安装库"
"fr" -> "Pour utiliser JWT, vous devez installer la bibliothèque"
"ko" -> "JWT를 사용하려면 라이브러리를 설치해야 합니다"


var spokenLang: cstring
Expand Down
2 changes: 1 addition & 1 deletion happyx.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

description = "Macro-oriented asynchronous web-framework written with ♥"
author = "HapticX"
version = "4.6.4"
version = "4.6.5"
license = "MIT"
srcDir = "src"
installExt = @["nim"]
Expand Down
5 changes: 3 additions & 2 deletions src/happyx/cli/dev_command.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import illwill except


proc devCommand*(host: string = "127.0.0.1", port: int = 5000,
reload: bool = false): int =
reload: bool = false, browser: bool = false): int =
## Serve
var
project = compileProject()
Expand Down Expand Up @@ -38,7 +38,8 @@ proc devCommand*(host: string = "127.0.0.1", port: int = 5000,
host = data[m.group(0)]
port = data[m.group(1)]
styledEcho "⚡ Server launched at ", fgGreen, styleUnderscore, "http://" & host & ":" & port, fgWhite
openDefaultBrowser("http://" & host & ":" & port & "/")
if browser:
openDefaultBrowser("http://" & host & ":" & port & "/")
while true:
styledEcho fgYellow, "if you want to quit from program, please input [q] char"
if stdin.readChar() == 'q':
Expand Down
2 changes: 1 addition & 1 deletion src/happyx/core/constants.nim
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ const
# Framework version
HpxMajor* = 4
HpxMinor* = 6
HpxPatch* = 4
HpxPatch* = 5
HpxVersion* = $HpxMajor & "." & $HpxMinor & "." & $HpxPatch


Expand Down
4 changes: 2 additions & 2 deletions src/happyx/core/secure.nim
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ using
] | string


proc generate_password*(source): MDigest[
func generate_password*(source): MDigest[
when cryptoMethod == "sha256":
256
elif cryptoMethod == "sha224":
Expand All @@ -44,7 +44,7 @@ proc generate_password*(source): MDigest[
sha3_512.digest(source)


proc check_password*(source, hash): bool =
func check_password*(source, hash): bool =
when cryptoMethod == "sha256":
$sha3_256.digest(source) == $hash
elif cryptoMethod == "sha384":
Expand Down
2 changes: 1 addition & 1 deletion src/happyx/hpx.nim
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ proc flagsCommandAux(): int = flagsCommand()
proc translateCsvCommandAux(filename: string, output: string = ""): int =
translateCsvCommand(filename, output)
proc devCommandAux(host: string = "127.0.0.1", port: int = 5000,
reload: bool = false): int =
reload: bool = false, browser: bool = false): int =
devCommand(host, port, reload)
proc createCommandAux(name: string = "", kind: string = "", templates: bool = false,
pathParams: bool = false, useTailwind: bool = false, language: string = ""): int =
Expand Down
31 changes: 31 additions & 0 deletions src/happyx/routing/decorators.nim
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import
std/macros,
std/tables,
std/strformat,
std/base64,
../core/constants

Expand Down Expand Up @@ -85,6 +86,34 @@ else:
let decoded = base64.decode(code).split(":", 1)
(decoded[0], decoded[1])"""
)


proc authBearerJwtDecoratorImpl(httpMethods: seq[string], routePath: string, statementList: NimNode, arguments: seq[NimNode]) =
let variableName = if arguments.len > 0: arguments[0] else: ident"jwtToken"
statementList.insert(0, parseStmt(fmt"""
var {variableName}: TableRef[system.string, claims.Claim]
if not headers.hasKey("Authorization"):
var statusCode = 401
return {{"response": "failure", "reason": "You should to be authorized!"}}
else:
if headers["Authorization"].startsWith("Bearer "):
{variableName} = headers["Authorization"][7..^1].toJWT.claims
else:
var statusCode = 401
return {{"response": "failure", "reason": "You should to be authorized!"}}""")
)


proc authJwtDecoratorImpl(httpMethods: seq[string], routePath: string, statementList: NimNode, arguments: seq[NimNode]) =
let variableName = if arguments.len > 0: arguments[0] else: ident"jwtToken"
statementList.insert(0, parseStmt(fmt"""
var {variableName}: TableRef[system.string, claims.Claim]
if not headers.hasKey("Authorization"):
var statusCode = 401
return {{"response": "failure", "reason": "You should to be authorized!"}}
else:
{variableName} = headers["Authorization"].toJWT.claims""")
)


proc getUserAgentDecoratorImpl(httpMethods: seq[string], routePath: string, statementList: NimNode, arguments: seq[NimNode]) =
Expand All @@ -96,4 +125,6 @@ var userAgent = navigator.userAgent

static:
regDecorator("AuthBasic", authBasicDecoratorImpl)
regDecorator("AuthBearerJWT", authBearerJwtDecoratorImpl)
regDecorator("AuthJWT", authJwtDecoratorImpl)
regDecorator("GetUserAgent", getUserAgentDecoratorImpl)
25 changes: 24 additions & 1 deletion tests/testc16.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import
../src/happyx
../src/happyx,
jwt


var x = generate_password("secret")
Expand Down Expand Up @@ -101,3 +102,25 @@ serve "127.0.0.1", 5000:
put "/post/$id:int":
## Edits a post
return "Hello, world!"

@AuthBasic
post "/test/basic-auth":
echo username # from @AuthBasic
echo password # from @AuthBasic
return "Hello, {username}!"

# You should install jwt library (https://github.com/yglukhov/nim-jwt)
# to use these decorators
# Authorization: JWT_TOKEN
@AuthJWT(token)
post "/test/jwt":
if token.hasKey("name"):
return "Hello, " & token["name"].node.str
return "who are you???"

# Authorization: Bearer JWT_TOKEN
@AuthBearerJWT(token)
post "/test/jwt-bearer":
if token.hasKey("name"):
return "Hello, " & token["name"].node.str
return "who are you???"

0 comments on commit 5476224

Please sign in to comment.