Add support for business and gov verification
Also improve icon rendering on Firefox
This commit is contained in:
		
							parent
							
								
									d6be08d093
								
							
						
					
					
						commit
						f8254c2f0f
					
				|  | @ -29,12 +29,10 @@ const | |||
|     "include_cards": "1", | ||||
|     "include_entities": "1", | ||||
|     "include_profile_interstitial_type": "0", | ||||
|     "include_quote_count": "1", | ||||
|     "include_reply_count": "1", | ||||
|     "include_user_entities": "1", | ||||
|     "include_ext_reply_count": "1", | ||||
|     "include_ext_is_blue_verified": "1", | ||||
|     # "include_ext_verified_type": "1", | ||||
|     "include_quote_count": "0", | ||||
|     "include_reply_count": "0", | ||||
|     "include_user_entities": "0", | ||||
|     "include_ext_reply_count": "0", | ||||
|     "include_ext_media_color": "0", | ||||
|     "cards_platform": "Web-13", | ||||
|     "tweet_mode": "extended", | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import options | ||||
| import jsony | ||||
| import user, ../types/[graphuser, graphlistmembers] | ||||
| from ../../types import User, Result, Query, QueryKind | ||||
| from ../../types import User, VerifiedType, Result, Query, QueryKind | ||||
| 
 | ||||
| proc parseGraphUser*(json: string): User = | ||||
|   if json.len == 0 or json[0] != '{': | ||||
|  | @ -14,7 +14,8 @@ proc parseGraphUser*(json: string): User = | |||
| 
 | ||||
|   result = raw.data.userResult.result.legacy | ||||
|   result.id = raw.data.userResult.result.restId | ||||
|   result.verified = result.verified or raw.data.userResult.result.isBlueVerified | ||||
|   if result.verifiedType == none and raw.data.userResult.result.isBlueVerified: | ||||
|     result.verifiedType = blue | ||||
| 
 | ||||
| proc parseGraphListMembers*(json, cursor: string): Result[User] = | ||||
|   result = Result[User]( | ||||
|  |  | |||
|  | @ -1,7 +1,6 @@ | |||
| import std/[options, tables, strutils, strformat, sugar] | ||||
| import jsony | ||||
| import user | ||||
| import ../types/unifiedcard | ||||
| import user, ../types/unifiedcard | ||||
| from ../../types import Card, CardKind, Video | ||||
| from ../../utils import twimg, https | ||||
| 
 | ||||
|  |  | |||
|  | @ -56,7 +56,7 @@ proc toUser*(raw: RawUser): User = | |||
|     tweets: raw.statusesCount, | ||||
|     likes: raw.favouritesCount, | ||||
|     media: raw.mediaCount, | ||||
|     verified: raw.verified or raw.extIsBlueVerified, | ||||
|     verifiedType: raw.verifiedType, | ||||
|     protected: raw.protected, | ||||
|     joinDate: parseTwitterDate(raw.createdAt), | ||||
|     banner: getBanner(raw), | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| import options | ||||
| import common | ||||
| from ../../types import VerifiedType | ||||
| 
 | ||||
| type | ||||
|   RawUser* = object | ||||
|  | @ -15,8 +16,7 @@ type | |||
|     favouritesCount*: int | ||||
|     statusesCount*: int | ||||
|     mediaCount*: int | ||||
|     verified*: bool | ||||
|     extIsBlueVerified*: bool | ||||
|     verifiedType*: VerifiedType | ||||
|     protected*: bool | ||||
|     profileLinkColor*: string | ||||
|     profileBannerUrl*: string | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ proc parseUser(js: JsonNode; id=""): User = | |||
|     tweets: js{"statuses_count"}.getInt, | ||||
|     likes: js{"favourites_count"}.getInt, | ||||
|     media: js{"media_count"}.getInt, | ||||
|     verified: js{"verified"}.getBool or js{"ext_is_blue_verified"}.getBool, | ||||
|     verifiedType: parseEnum[VerifiedType](js{"verified_type"}.getStr("None")), | ||||
|     protected: js{"protected"}.getBool, | ||||
|     joinDate: js{"created_at"}.getTime | ||||
|   ) | ||||
|  | @ -34,8 +34,8 @@ proc parseGraphUser(js: JsonNode): User = | |||
|     user = ? js{"user_results", "result"} | ||||
|   result = parseUser(user{"legacy"}) | ||||
| 
 | ||||
|   if "is_blue_verified" in user: | ||||
|     result.verified = user{"is_blue_verified"}.getBool() | ||||
|   if result.verifiedType == none and user{"is_blue_verified"}.getBool(false): | ||||
|     result.verifiedType = blue | ||||
| 
 | ||||
| proc parseGraphList*(js: JsonNode): List = | ||||
|   if js.isNull: return | ||||
|  |  | |||
|  | @ -52,6 +52,7 @@ proc initRedisPool*(cfg: Config) {.async.} = | |||
|     await migrate("profileDates", "p:*") | ||||
|     await migrate("profileStats", "p:*") | ||||
|     await migrate("userType", "p:*") | ||||
|     await migrate("verifiedType", "p:*") | ||||
| 
 | ||||
|     pool.withAcquire(r): | ||||
|       # optimize memory usage for user ID buckets | ||||
|  |  | |||
|  | @ -28,6 +28,8 @@ $more_replies_dots: #AD433B; | |||
| $error_red: #420A05; | ||||
| 
 | ||||
| $verified_blue: #1DA1F2; | ||||
| $verified_business: #FAC82B; | ||||
| $verified_government: #C1B6A4; | ||||
| $icon_text: $fg_color; | ||||
| 
 | ||||
| $tab: $fg_color; | ||||
|  |  | |||
|  | @ -39,6 +39,8 @@ body { | |||
|     --error_red: #{$error_red}; | ||||
| 
 | ||||
|     --verified_blue: #{$verified_blue}; | ||||
|     --verified_business: #{$verified_business}; | ||||
|     --verified_government: #{$verified_government}; | ||||
|     --icon_text: #{$icon_text}; | ||||
| 
 | ||||
|     --tab: #{$fg_color}; | ||||
|  | @ -141,17 +143,30 @@ ul { | |||
| 
 | ||||
| .verified-icon { | ||||
|     color: var(--icon_text); | ||||
|     background-color: var(--verified_blue); | ||||
|     border-radius: 50%; | ||||
|     flex-shrink: 0; | ||||
|     margin: 2px 0 3px 3px; | ||||
|     padding-top: 2px; | ||||
|     height: 12px; | ||||
|     padding-top: 3px; | ||||
|     height: 11px; | ||||
|     width: 14px; | ||||
|     font-size: 8px; | ||||
|     display: inline-block; | ||||
|     text-align: center; | ||||
|     vertical-align: middle; | ||||
| 
 | ||||
|     &.blue { | ||||
|         background-color: var(--verified_blue); | ||||
|     } | ||||
| 
 | ||||
|     &.business { | ||||
|         color: var(--bg_panel); | ||||
|         background-color: var(--verified_business); | ||||
|     } | ||||
| 
 | ||||
|     &.government { | ||||
|         color: var(--bg_panel); | ||||
|         background-color: var(--verified_government); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @media(max-width: 600px) { | ||||
|  |  | |||
|  | @ -14,6 +14,8 @@ | |||
|     button { | ||||
|         margin: 0 2px 0 0; | ||||
|         height: 23px; | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|     } | ||||
| 
 | ||||
|     .pref-input { | ||||
|  |  | |||
|  | @ -10,9 +10,7 @@ type | |||
|   BadClientError* = object of CatchableError | ||||
| 
 | ||||
|   TimelineKind* {.pure.} = enum | ||||
|     tweets | ||||
|     replies | ||||
|     media | ||||
|     tweets, replies, media | ||||
| 
 | ||||
|   Api* {.pure.} = enum | ||||
|     tweetDetail | ||||
|  | @ -63,6 +61,12 @@ type | |||
|     tweetUnavailable = 421 | ||||
|     tweetCensored = 422 | ||||
| 
 | ||||
|   VerifiedType* = enum | ||||
|     none = "None" | ||||
|     blue = "Blue" | ||||
|     business = "Business" | ||||
|     government = "Government" | ||||
| 
 | ||||
|   User* = object | ||||
|     id*: string | ||||
|     username*: string | ||||
|  | @ -78,7 +82,7 @@ type | |||
|     tweets*: int | ||||
|     likes*: int | ||||
|     media*: int | ||||
|     verified*: bool | ||||
|     verifiedType*: VerifiedType | ||||
|     protected*: bool | ||||
|     suspended*: bool | ||||
|     joinDate*: DateTime | ||||
|  |  | |||
|  | @ -52,7 +52,7 @@ proc renderHead*(prefs: Prefs; cfg: Config; req: Request; titleText=""; desc=""; | |||
|   let opensearchUrl = getUrlPrefix(cfg) & "/opensearch" | ||||
| 
 | ||||
|   buildHtml(head): | ||||
|     link(rel="stylesheet", type="text/css", href="/css/style.css?v=18") | ||||
|     link(rel="stylesheet", type="text/css", href="/css/style.css?v=19") | ||||
|     link(rel="stylesheet", type="text/css", href="/css/fontello.css?v=2") | ||||
| 
 | ||||
|     if theme.len > 0: | ||||
|  |  | |||
|  | @ -23,6 +23,13 @@ proc icon*(icon: string; text=""; title=""; class=""; href=""): VNode = | |||
|     if text.len > 0: | ||||
|       text " " & text | ||||
| 
 | ||||
| template verifiedIcon*(user: User): untyped {.dirty.} = | ||||
|   if user.verifiedType != none: | ||||
|     let lower = ($user.verifiedType).toLowerAscii() | ||||
|     icon "ok", class=(&"verified-icon {lower}"), title=(&"Verified {lower} account") | ||||
|   else: | ||||
|     text "" | ||||
| 
 | ||||
| proc linkUser*(user: User, class=""): VNode = | ||||
|   let | ||||
|     isName = "username" notin class | ||||
|  | @ -32,11 +39,11 @@ proc linkUser*(user: User, class=""): VNode = | |||
| 
 | ||||
|   buildHtml(a(href=href, class=class, title=nameText)): | ||||
|     text nameText | ||||
|     if isName and user.verified: | ||||
|       icon "ok", class="verified-icon", title="Verified account" | ||||
|     if isName and user.protected: | ||||
|       text " " | ||||
|       icon "lock", title="Protected account" | ||||
|     if isName: | ||||
|       verifiedIcon(user) | ||||
|       if user.protected: | ||||
|         text " " | ||||
|         icon "lock", title="Protected account" | ||||
| 
 | ||||
| proc linkText*(text: string; class=""): VNode = | ||||
|   let url = if "http" notin text: https & text else: text | ||||
|  |  | |||
|  | @ -200,8 +200,7 @@ proc renderAttribution(user: User; prefs: Prefs): VNode = | |||
|   buildHtml(a(class="attribution", href=("/" & user.username))): | ||||
|     renderMiniAvatar(user, prefs) | ||||
|     strong: text user.fullname | ||||
|     if user.verified: | ||||
|       icon "ok", class="verified-icon", title="Verified account" | ||||
|     verifiedIcon(user) | ||||
| 
 | ||||
| proc renderMediaTags(tags: seq[User]): VNode = | ||||
|   buildHtml(tdiv(class="media-tag-block")): | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue