diff --git a/.travis.yml b/.travis.yml index b6177c4..b5c6c9b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ cache: - "$HOME/.choosenim" addons: - firefox: "60.0.1" + firefox: "73.0" before_install: - sudo apt-get -qq update @@ -26,13 +26,13 @@ before_install: - sudo make -j5 install - cd .. - - wget https://github.com/mozilla/geckodriver/releases/download/v0.20.1/geckodriver-v0.20.1-linux64.tar.gz + - wget https://github.com/mozilla/geckodriver/releases/download/v0.26.0/geckodriver-v0.26.0-linux64.tar.gz - mkdir geckodriver - - tar -xzf geckodriver-v0.20.1-linux64.tar.gz -C geckodriver + - tar -xzf geckodriver-v0.26.0-linux64.tar.gz -C geckodriver - export PATH=$PATH:$PWD/geckodriver install: - - export CHOOSENIM_CHOOSE_VERSION="#f92d61b1f4e193bd" + - export CHOOSENIM_CHOOSE_VERSION="stable" - | curl https://nim-lang.org/choosenim/init.sh -sSf > init.sh sh init.sh -y @@ -41,4 +41,5 @@ install: script: - export MOZ_HEADLESS=1 - - nimble -y test \ No newline at end of file + - nimble -y install + - nimble -y test diff --git a/nimforum.nimble b/nimforum.nimble index 79c43af..97581b0 100644 --- a/nimforum.nimble +++ b/nimforum.nimble @@ -1,5 +1,5 @@ # Package -version = "2.1.0" +version = "2.0.2" author = "Dominik Picheta" description = "The Nim forum" license = "MIT" @@ -12,16 +12,16 @@ skipExt = @["nim"] # Dependencies -requires "nim >= 0.18.1" -requires "jester#22f8240" +requires "nim >= 1.0.6" +requires "jester#d8a03aa" requires "bcrypt#head" requires "hmac#9c61ebe2fd134cf97" -requires "recaptcha 1.0.2" +requires "recaptcha#d06488e" requires "sass#649e0701fa5c" -requires "karax#c8c7b13" +requires "karax#f6bda9a" -requires "webdriver#20f3c1b" +requires "webdriver#c2fee57" # Tasks @@ -36,7 +36,7 @@ task frontend, "Builds the necessary JS frontend (with CSS)": exec "nimble c -r src/buildcss" exec "nimble js -d:release src/frontend/forum.nim" mkDir "public/js" - cpFile "src/frontend/nimcache/forum.js", "public/js/forum.js" + cpFile "src/frontend/forum.js", "public/js/forum.js" task minify, "Minifies the JS using Google's closure compiler": exec "closure-compiler public/js/forum.js --js_output_file public/js/forum.js.opt" diff --git a/public/css/nimforum.scss b/public/css/nimforum.scss index ead7b0e..9842d8d 100644 --- a/public/css/nimforum.scss +++ b/public/css/nimforum.scss @@ -269,6 +269,13 @@ $threads-meta-color: #545d70; } +// Hide all the avatars but the first on small screens. +@media screen and (max-width: 600px) { + #threads-list a:not(:first-child) > .avatar { + display: none; + } +} + .posts, .about { @extend .grid-md; @extend .container; diff --git a/setup.md b/setup.md index ea3dc1b..d0f2d3e 100644 --- a/setup.md +++ b/setup.md @@ -100,7 +100,7 @@ You should then create a symlink to this file inside ``/etc/nginx/sites-enabled/ ln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/ ``` -Then restart nginx by running ``sudo systemctl restart nginx``. +Then reload nginx configuration by running ``sudo nginx -s reload``. ### Supervisor @@ -168,4 +168,4 @@ You should see something like this: ## Conclusion That should be all you need to get started. Your forum should now be accessible -via your hostname, assuming that it points to your VPS' IP address. \ No newline at end of file +via your hostname, assuming that it points to your VPS' IP address. diff --git a/src/forum.nim b/src/forum.nim index 303d801..a551b73 100644 --- a/src/forum.nim +++ b/src/forum.nim @@ -457,13 +457,21 @@ proc executeReply(c: TForumData, threadId: int, content: string, if isLocked == "1": raise newForumError("Cannot reply to a locked thread.") - let retID = insertID( - db, - crud(crCreate, "post", "author", "ip", "content", "thread", "replyingTo"), - c.userId, c.req.ip, content, $threadId, - if replyingTo.isSome(): $replyingTo.get() - else: "" - ) + var retID: int64 + + if replyingTo.isSome(): + retID = insertID( + db, + crud(crCreate, "post", "author", "ip", "content", "thread", "replyingTo"), + c.userId, c.req.ip, content, $threadId, $replyingTo.get() + ) + else: + retID = insertID( + db, + crud(crCreate, "post", "author", "ip", "content", "thread"), + c.userId, c.req.ip, content, $threadId + ) + discard tryExec( db, crud(crCreate, "post_fts", "id", "content"), @@ -621,7 +629,7 @@ proc executeRegister(c: TForumData, name, pass, antibot, userIp, raise newForumError("Invalid username", @["username"]) if getValue( db, - sql"select name from person where name = ? and isDeleted = 0", + sql"select name from person where name = ? collate nocase and isDeleted = 0", name ).len > 0: raise newForumError("Username already exists", @["username"]) @@ -1123,7 +1131,8 @@ routes: except EParseError: let err = PostError( errorFields: @[], - message: getCurrentExceptionMsg() + message: "Message needs to be valid RST! Error: " & + getCurrentExceptionMsg() ) resp Http400, $(%err), "application/json" diff --git a/src/frontend/error.nim b/src/frontend/error.nim index 54d495b..06a8d07 100644 --- a/src/frontend/error.nim +++ b/src/frontend/error.nim @@ -90,4 +90,4 @@ when defined(js): state.error = some(PostError( errorFields: @[], message: "Unknown error occurred." - )) \ No newline at end of file + )) diff --git a/src/frontend/karaxutils.nim b/src/frontend/karaxutils.nim index 462d000..2aa9d39 100644 --- a/src/frontend/karaxutils.nim +++ b/src/frontend/karaxutils.nim @@ -25,7 +25,7 @@ proc getInt64*(s: string, default = 0): int64 = when defined(js): include karax/prelude - import karax / [kdom] + import karax / [kdom, kajax] from dom import nil @@ -87,16 +87,10 @@ when defined(js): navigateTo(url) - type - FormData* = ref object - proc newFormData*(): FormData - {.importcpp: "new FormData()", constructor.} proc newFormData*(form: dom.Element): FormData {.importcpp: "new FormData(@)", constructor.} proc get*(form: FormData, key: cstring): cstring {.importcpp: "#.get(@)".} - proc append*(form: FormData, key, val: cstring) - {.importcpp: "#.append(@)".} proc renderProfileUrl*(username: string): string = makeUri(fmt"/profile/{username}") @@ -120,4 +114,4 @@ when defined(js): inc(i) # Skip = i += query.parseUntil(val, '&', i) inc(i) # Skip & - result[$decodeUri(key)] = $decodeUri(val) \ No newline at end of file + result[$decodeUri(key)] = $decodeUri(val) diff --git a/src/frontend/login.nim b/src/frontend/login.nim index f0779c7..c19088e 100644 --- a/src/frontend/login.nim +++ b/src/frontend/login.nim @@ -1,6 +1,6 @@ when defined(js): import sugar, httpcore, options, json - import dom except Event + import dom except Event, KeyboardEvent include karax/prelude import karax / [kajax, kdom] @@ -93,4 +93,4 @@ when defined(js): (state.onSignUp(); state.shown = false)): text "Create account" - render(state.resetPasswordModal, recaptchaSiteKey) \ No newline at end of file + render(state.resetPasswordModal, recaptchaSiteKey) diff --git a/src/frontend/replybox.nim b/src/frontend/replybox.nim index c7e61cc..e386dcb 100644 --- a/src/frontend/replybox.nim +++ b/src/frontend/replybox.nim @@ -26,7 +26,7 @@ when defined(js): proc performScroll() = let replyBox = dom.document.getElementById("reply-box") - replyBox.scrollIntoView(false) + replyBox.scrollIntoView() proc show*(state: ReplyBox) = # Scroll to the reply box. diff --git a/src/frontend/resetpassword.nim b/src/frontend/resetpassword.nim index c2f01a1..51b467b 100644 --- a/src/frontend/resetpassword.nim +++ b/src/frontend/resetpassword.nim @@ -1,6 +1,6 @@ when defined(js): import sugar, httpcore, options, json - import dom except Event + import dom except Event, KeyboardEvent include karax/prelude import karax / [kajax, kdom] @@ -152,4 +152,4 @@ when defined(js): ), `type`="button", onClick=(ev: Event, n: VNode) => onClick(ev, n, state)): - text "Reset password" \ No newline at end of file + text "Reset password" diff --git a/src/utils.nim b/src/utils.nim index 2676ab8..1be058b 100644 --- a/src/utils.nim +++ b/src/utils.nim @@ -10,11 +10,6 @@ let import frontend/[karaxutils, error] export parseInt -proc `%`*[T](opt: Option[T]): JsonNode = - ## Generic constructor for JSON data. Creates a new ``JNull JsonNode`` - ## if ``opt`` is empty, otherwise it delegates to the underlying value. - if opt.isSome: %opt.get else: newJNull() - type Config* = object smtpAddress*: string @@ -56,7 +51,7 @@ proc loadConfig*(filename = getCurrentDir() / "forum.json"): Config = smtpPassword: "", mlistAddress: "") let root = parseFile(filename) result.smtpAddress = root{"smtpAddress"}.getStr("") - result.smtpPort = root{"smtpPort"}.getNum(25).int + result.smtpPort = root{"smtpPort"}.getInt(25) result.smtpUser = root{"smtpUser"}.getStr("") result.smtpPassword = root{"smtpPassword"}.getStr("") result.smtpFromAddr = root{"smtpFromAddr"}.getStr("") @@ -69,7 +64,7 @@ proc loadConfig*(filename = getCurrentDir() / "forum.json"): Config = result.name = root["name"].getStr() result.title = root["title"].getStr() result.ga = root{"ga"}.getStr() - result.port = root{"port"}.getNum(5000).int + result.port = root{"port"}.getInt(5000) proc processGT(n: XmlNode, tag: string): (int, XmlNode, string) = result = (0, newElement(tag), tag) diff --git a/tests/browsertests/common.nim b/tests/browsertests/common.nim index b3a093c..02236ca 100644 --- a/tests/browsertests/common.nim +++ b/tests/browsertests/common.nim @@ -115,7 +115,7 @@ proc login*(session: Session, user, password: string) = checkText "#profile-btn #profile-name", user click "#profile-btn" -proc register*(session: Session, user, password: string) = +proc register*(session: Session, user, password: string, verify = true) = with session: click "#signup-btn" @@ -130,11 +130,13 @@ proc register*(session: Session, user, password: string) = click "#signup-modal .create-account-btn" wait() - # Verify that the user menu has been initialised properly. - click "#profile-btn" - checkText "#profile-btn #profile-name", user - # close menu - click "#profile-btn" + if verify: + with session: + # Verify that the user menu has been initialised properly. + click "#profile-btn" + checkText "#profile-btn #profile-name", user + # close menu + click "#profile-btn" proc createThread*(session: Session, title, content: string) = with session: diff --git a/tests/browsertests/scenario1.nim b/tests/browsertests/scenario1.nim index 34132e5..b5912ec 100644 --- a/tests/browsertests/scenario1.nim +++ b/tests/browsertests/scenario1.nim @@ -30,5 +30,18 @@ proc test*(session: Session, baseUrl: string) = test "can register": with session: register("test", "test") + logout() - session.logout() + test "can't register same username with different case": + with session: + register "test1", "test1", verify = false + logout() + + navigate baseUrl + wait() + + register "TEst1", "test1", verify = false + + ensureExists "#signup-form .has-error" + navigate baseUrl + wait() \ No newline at end of file