From bd774cf0cab26a02160107fe34a3cfa12dbce7e9 Mon Sep 17 00:00:00 2001 From: Zed Date: Thu, 19 Sep 2019 02:23:22 +0200 Subject: [PATCH] Make queries non-optional --- src/api/search.nim | 6 +++--- src/api/timeline.nim | 4 ++-- src/parser.nim | 2 +- src/query.nim | 2 +- src/routes/rss.nim | 8 ++++---- src/routes/timeline.nim | 28 +++++++++++++-------------- src/types.nim | 4 ++-- src/views/profile.nim | 4 +--- src/views/search.nim | 42 +++++++++++++++-------------------------- src/views/timeline.nim | 12 ++++++------ 10 files changed, 48 insertions(+), 64 deletions(-) diff --git a/src/api/search.nim b/src/api/search.nim index 67f0477..7f4e02f 100644 --- a/src/api/search.nim +++ b/src/api/search.nim @@ -9,7 +9,7 @@ proc getResult[T](json: JsonNode; query: Query; after: string): Result[T] = hasMore: json["has_more_items"].to(bool), maxId: json.getOrDefault("max_position").getStr(""), minId: json.getOrDefault("min_position").getStr("").cleanPos(), - query: some query, + query: query, beginning: after.len == 0 ) @@ -42,14 +42,14 @@ proc getSearch*[T](query: Query; after, agent: string): Future[Result[T]] {.asyn } let json = await fetchJson(base / searchUrl ? params, headers) - if json == nil: return Result[T](query: some query) + if json == nil: return Result[T](query: query) result = getResult[T](json, query, after) if not json.hasKey("items_html"): return let html = parseHtml(json["items_html"].to(string)) when T is Tweet: - result = await finishTimeline(json, some query, after, agent) + result = await finishTimeline(json, query, after, agent) elif T is Profile: result.hasMore = json["items_html"].to(string) != "\n" for p in html.selectAll(".js-stream-item"): diff --git a/src/api/timeline.nim b/src/api/timeline.nim index ae75245..f54a68c 100644 --- a/src/api/timeline.nim +++ b/src/api/timeline.nim @@ -4,7 +4,7 @@ import sequtils, strutils, json, xmltree, uri import ".."/[types, parser, parserutils, formatters, query] import utils, consts, media -proc finishTimeline*(json: JsonNode; query: Option[Query]; after, agent: string): Future[Timeline] {.async.} = +proc finishTimeline*(json: JsonNode; query: Query; after, agent: string): Future[Timeline] {.async.} = if json == nil: return Timeline() result = Timeline( @@ -49,7 +49,7 @@ proc getTimeline*(username, after, agent: string): Future[Timeline] {.async.} = params.add {"max_position": after} let json = await fetchJson(base / (timelineUrl % username) ? params, headers) - result = await finishTimeline(json, none Query, after, agent) + result = await finishTimeline(json, Query(), after, agent) proc getProfileAndTimeline*(username, agent, after: string): Future[(Profile, Timeline)] {.async.} = let headers = newHttpHeaders({ diff --git a/src/parser.nim b/src/parser.nim index 90ff116..f59ce2d 100644 --- a/src/parser.nim +++ b/src/parser.nim @@ -157,7 +157,7 @@ proc parseConversation*(node: XmlNode): Conversation = result.replies.add parseThread(thread) proc parseTimeline*(node: XmlNode; after: string): Timeline = - if node == nil: return + if node == nil: return Timeline() result = Timeline( content: parseThread(node.select(".stream > .stream-items")).content, minId: node.attr("data-min-position"), diff --git a/src/query.nim b/src/query.nim index 1227da3..5c44dd5 100644 --- a/src/query.nim +++ b/src/query.nim @@ -78,7 +78,7 @@ proc genQueryUrl*(query: Query): string = if query.fromUser.len > 0: result = "/" & query.fromUser.join(",") - if query.kind == multi: + if query.fromUser.len > 1: return result & "?" if query.kind notin {custom, users}: diff --git a/src/routes/rss.nim b/src/routes/rss.nim index 7c99ab2..d4529f7 100644 --- a/src/routes/rss.nim +++ b/src/routes/rss.nim @@ -8,7 +8,7 @@ import ../views/general include "../views/rss.nimf" -proc showRss*(name: string; query: Option[Query]): Future[string] {.async.} = +proc showRss*(name: string; query: Query): Future[string] {.async.} = let (profile, timeline, _) = await fetchSingleTimeline(name, "", getAgent(), query) return renderTimelineRss(timeline.content, profile) @@ -21,12 +21,12 @@ proc createRssRouter*(cfg: Config) = router rss: get "/@name/rss": cond '.' notin @"name" - respRss(await showRss(@"name", none Query)) + respRss(await showRss(@"name", Query())) get "/@name/replies/rss": cond '.' notin @"name" - respRss(await showRss(@"name", some getReplyQuery(@"name"))) + respRss(await showRss(@"name", getReplyQuery(@"name"))) get "/@name/media/rss": cond '.' notin @"name" - respRss(await showRss(@"name", some getMediaQuery(@"name"))) + respRss(await showRss(@"name", getMediaQuery(@"name"))) diff --git a/src/routes/timeline.nim b/src/routes/timeline.nim index e35f741..92fcf8c 100644 --- a/src/routes/timeline.nim +++ b/src/routes/timeline.nim @@ -16,7 +16,7 @@ export profile, timeline, status type ProfileTimeline = (Profile, Timeline, seq[GalleryPhoto]) proc fetchSingleTimeline*(name, after, agent: string; - query: Option[Query]): Future[ProfileTimeline] {.async.} = + query: Query): Future[ProfileTimeline] {.async.} = let railFut = getPhotoRail(name, agent) var timeline: Timeline @@ -26,14 +26,14 @@ proc fetchSingleTimeline*(name, after, agent: string; if cachedProfile.isSome: profile = get(cachedProfile) - if query.isNone: + if query.kind == posts: if cachedProfile.isSome: timeline = await getTimeline(name, after, agent) else: (profile, timeline) = await getProfileAndTimeline(name, agent, after) cache(profile) else: - var timelineFut = getSearch[Tweet](get(query), after, agent) + var timelineFut = getSearch[Tweet](query, after, agent) if cachedProfile.isNone: profile = await getCachedProfile(name, agent) timeline = await timelineFut @@ -42,16 +42,14 @@ proc fetchSingleTimeline*(name, after, agent: string; return (profile, timeline, await railFut) proc fetchMultiTimeline*(names: seq[string]; after, agent: string; - query: Option[Query]): Future[Timeline] {.async.} = + query: Query): Future[Timeline] {.async.} = var q = query - if q.isSome: - get(q).fromUser = names - else: - q = some Query(kind: multi, fromUser: names, excludes: @["replies"]) + q.fromUser = names + if q.kind == posts and "replies" notin q.excludes: + q.excludes.add "replies" + return await getSearch[Tweet](q, after, agent) - return await getSearch[Tweet](get(q), after, agent) - -proc showTimeline*(name, after: string; query: Option[Query]; +proc showTimeline*(name, after: string; query: Query; prefs: Prefs; path, title, rss: string): Future[string] {.async.} = let agent = getAgent() let names = name.strip(chars={'/'}).split(",").filterIt(it.len > 0) @@ -79,25 +77,25 @@ proc createTimelineRouter*(cfg: Config) = get "/@name/?": cond '.' notin @"name" let rss = "/$1/rss" % @"name" - respTimeline(await showTimeline(@"name", @"after", none Query, cookiePrefs(), + respTimeline(await showTimeline(@"name", @"after", Query(), cookiePrefs(), getPath(), cfg.title, rss)) get "/@name/search": cond '.' notin @"name" - let query = some initQuery(params(request), name=(@"name")) + let query = initQuery(params(request), name=(@"name")) respTimeline(await showTimeline(@"name", @"after", query, cookiePrefs(), getPath(), cfg.title, "")) get "/@name/replies": cond '.' notin @"name" let rss = "/$1/replies/rss" % @"name" - respTimeline(await showTimeline(@"name", @"after", some getReplyQuery(@"name"), + respTimeline(await showTimeline(@"name", @"after", getReplyQuery(@"name"), cookiePrefs(), getPath(), cfg.title, rss)) get "/@name/media": cond '.' notin @"name" let rss = "/$1/media/rss" % @"name" - respTimeline(await showTimeline(@"name", @"after", some getMediaQuery(@"name"), + respTimeline(await showTimeline(@"name", @"after", getMediaQuery(@"name"), cookiePrefs(), getPath(), cfg.title, rss)) get "/@name/status/@id": diff --git a/src/types.nim b/src/types.nim index 327976a..03d01af 100644 --- a/src/types.nim +++ b/src/types.nim @@ -57,7 +57,7 @@ dbFromTypes("cache.db", "", "", "", [Profile, Video]) type QueryKind* = enum - posts, replies, media, multi, users, custom + posts, replies, media, users, custom Query* = object kind*: QueryKind @@ -74,7 +74,7 @@ type maxId*: string hasMore*: bool beginning*: bool - query*: Option[Query] + query*: Query Gif* = object url*: string diff --git a/src/views/profile.nim b/src/views/profile.nim index 9fd2d6b..694bd78 100644 --- a/src/views/profile.nim +++ b/src/views/profile.nim @@ -83,9 +83,7 @@ proc renderProtected(username: string): VNode = proc renderProfile*(profile: Profile; timeline: Timeline; photoRail: seq[GalleryPhoto]; prefs: Prefs; path: string): VNode = - if timeline.query.isNone: - timeline.query = some Query(fromUser: @[profile.username]) - + timeline.query.fromUser = @[profile.username] buildHtml(tdiv(class="profile-tabs")): if not prefs.hideBanner: tdiv(class="profile-banner"): diff --git a/src/views/search.nim b/src/views/search.nim index c041da4..18c9ed4 100644 --- a/src/views/search.nim +++ b/src/views/search.nim @@ -27,36 +27,31 @@ proc renderSearch*(): VNode = input(`type`="text", name="text", autofocus="", placeholder="Enter username...") button(`type`="submit"): icon "search" -proc getTabClass(query: Option[Query]; tab: string): string = +proc getTabClass(query: Query; tab: QueryKind): string = var classes = @["tab-item"] - - if query.isNone or get(query).kind == multi: - if tab == "posts": - classes.add "active" - elif $get(query).kind == tab: + if query.kind == tab: classes.add "active" - return classes.join(" ") -proc renderProfileTabs*(query: Option[Query]; username: string): VNode = +proc renderProfileTabs*(query: Query; username: string): VNode = let link = "/" & username buildHtml(ul(class="tab")): - li(class=query.getTabClass("posts")): + li(class=query.getTabClass(posts)): a(href=link): text "Tweets" - li(class=query.getTabClass("replies")): + li(class=query.getTabClass(replies)): a(href=(link & "/replies")): text "Tweets & Replies" - li(class=query.getTabClass("media")): + li(class=query.getTabClass(media)): a(href=(link & "/media")): text "Media" - li(class=query.getTabClass("custom")): + li(class=query.getTabClass(custom)): a(href=(link & "/search")): text "Custom" -proc renderSearchTabs*(query: Option[Query]): VNode = - var q = if query.isSome: get(query) else: Query() +proc renderSearchTabs*(query: Query): VNode = + var q = query buildHtml(ul(class="tab")): - li(class=query.getTabClass("custom")): + li(class=query.getTabClass(custom)): q.kind = custom a(href=genQueryUrl(q)): text "Tweets" - li(class=query.getTabClass("users")): + li(class=query.getTabClass(users)): q.kind = users a(href=genQueryUrl(q)): text "Users" @@ -81,10 +76,7 @@ proc renderSearchPanel*(query: Query): VNode = genCheckbox(&"{f[0]}-{k}", v, state) proc renderTweetSearch*(tweets: Result[Tweet]; prefs: Prefs; path: string): VNode = - let query = - if tweets.query.isSome: get(tweets.query) - else: Query(kind: custom) - + let query = tweets.query buildHtml(tdiv(class="timeline-container")): if query.fromUser.len > 1: tdiv(class="timeline-header"): @@ -94,22 +86,18 @@ proc renderTweetSearch*(tweets: Result[Tweet]; prefs: Prefs; path: string): VNod renderSearchPanel(query) if query.fromUser.len > 0: - renderProfileTabs(tweets.query, query.fromUser.join(",")) + renderProfileTabs(query, query.fromUser.join(",")) else: - renderSearchTabs(tweets.query) + renderSearchTabs(query) renderTimelineTweets(tweets, prefs, path) proc renderUserSearch*(users: Result[Profile]; prefs: Prefs): VNode = - let searchText = - if users.query.isSome: get(users.query).text - else: "" - buildHtml(tdiv(class="timeline-container")): tdiv(class="timeline-header"): form(`method`="get", action="/search", class="search-field"): hiddenField("kind", "users") - genInput("text", "", searchText, "Enter username...", class="pref-inline") + genInput("text", "", users.query.text, "Enter username...", class="pref-inline") button(`type`="submit"): icon "search" renderSearchTabs(users.query) diff --git a/src/views/timeline.nim b/src/views/timeline.nim index 362f178..034fadb 100644 --- a/src/views/timeline.nim +++ b/src/views/timeline.nim @@ -4,20 +4,20 @@ import karax/[karaxdsl, vdom, vstyles] import ".."/[types, query, formatters] import tweet, renderutils -proc getQuery(query: Option[Query]): string = - if query.isNone: +proc getQuery(query: Query): string = + if query.kind == posts: result = "?" else: - result = genQueryUrl(get(query)) + result = genQueryUrl(query) if result[^1] != '?': result &= "&" -proc renderNewer(query: Option[Query]): VNode = +proc renderNewer(query: Query): VNode = buildHtml(tdiv(class="timeline-item show-more")): a(href=(getQuery(query).strip(chars={'?', '&'}))): text "Load newest" -proc renderOlder(query: Option[Query]; minId: string): VNode = +proc renderOlder(query: Query; minId: string): VNode = buildHtml(tdiv(class="show-more")): a(href=(&"{getQuery(query)}after={minId}")): text "Load older" @@ -88,7 +88,7 @@ proc renderTimelineTweets*(results: Result[Tweet]; prefs: Prefs; path: string): renderThread(thread, prefs, path) threads &= tweet.threadId - if results.hasMore or results.query.isSome: + if results.hasMore or results.query.kind != posts: renderOlder(results.query, results.minId) else: renderNoMore()