Commit 8a6978cf authored by Zed's avatar Zed

Detect suspended accounts

parent 240ce156
Pipeline #934 passed with stage
in 3 minutes and 55 seconds
import asyncdispatch, strutils, uri
import asyncdispatch, strutils, uri, httpclient, json, xmltree, htmlparser
import ".."/[types, parser]
import utils, consts, media
......@@ -7,11 +7,21 @@ proc getTweet*(username, id, after, agent: string): Future[Conversation] {.async
let
headers = genHeaders({
"pragma": "no-cache",
"x-previous-page-name": "profile"
"x-previous-page-name": "profile",
"accept": htmlAccept
}, agent, base, xml=true)
url = base / username / tweetUrl / id ? {"max_position": after}
html = await fetchHtml(url, headers)
newClient()
var html: XmlNode
try:
let resp = await client.get($url)
if resp.code == Http403 and "suspended" in (await resp.body):
return Conversation(tweet: Tweet(tombstone: "User has been suspended"))
html = parseHtml(await resp.body)
except:
discard
if html == nil: return
......
......@@ -15,6 +15,7 @@ withDb:
except DbError: discard
safeAddColumn Profile.lowername
safeAddColumn Profile.suspended
var profileCacheTime = initDuration(minutes=10)
......
......@@ -127,3 +127,6 @@ proc getLocation*(u: Profile | Tweet): (string, string) =
let loc = u.location.split(":")
let url = if loc.len > 1: "/search?q=place:" & loc[1] else: ""
(loc[0], url)
proc getSuspended*(username: string): string =
&"User \"{username}\" has been suspended"
......@@ -2,9 +2,19 @@ import xmltree, sequtils, strutils, json, options
import types, parserutils, formatters
proc parseJsonData*(node: XmlNode): JsonNode =
let jsonData = node.selectAttr("input.json-data", "value")
if jsonData.len > 0:
return parseJson(jsonData)
proc parseTimelineProfile*(node: XmlNode): Profile =
let profile = node.select(".ProfileHeaderCard")
if profile == nil: return
if profile == nil:
let data = parseJsonData(node)
if data != nil and data{"sectionName"}.getStr == "suspended":
let username = data{"internalReferer"}.getStr.strip(chars={'/'})
return Profile(username: username, suspended: true)
return
let pre = ".ProfileHeaderCard-"
let username = profile.getUsername(pre & "screenname")
......
......@@ -29,6 +29,9 @@ proc showRss*(req: Request; hostname: string; query: Query): Future[(string, str
userpic: "https://abs.twimg.com/sticky/default_profile_images/default_profile.png"
)
if profile.suspended:
return (profile.username, "suspended")
if timeline != nil:
let rss = renderTimelineRss(timeline, profile, hostname, multi=(names.len > 1))
return (rss, timeline.minId)
......@@ -36,6 +39,8 @@ proc showRss*(req: Request; hostname: string; query: Query): Future[(string, str
template respRss*(rss, minId) =
if rss.len == 0:
resp Http404, showError("User \"" & @"name" & "\" not found", cfg)
elif minId == "suspended":
resp Http404, showError(getSuspended(rss), cfg)
let headers = {"Content-Type": "application/rss+xml;charset=utf-8", "Min-Id": minId}
resp Http200, headers, rss
......
......@@ -71,6 +71,9 @@ proc showTimeline*(request: Request; query: Query; cfg: Config; prefs: Prefs;
(p, t) = await fetchSingleTimeline(names[0], after, agent, query)
r = await rail
if p.username.len == 0: return
if p.suspended:
return showError(getSuspended(p.username), cfg)
let pHtml = renderProfile(p, t, r, prefs, getPath())
return renderMain(pHtml, request, cfg, pageTitle(p), pageDesc(p),
rss=rss, images = @[p.getUserpic("_200x200")])
......
......@@ -25,6 +25,7 @@ dbTypes:
media*: string
verified*: bool
protected*: bool
suspended*: bool
joinDate* {.
dbType: "INTEGER"
parseIt: it.i.fromUnix()
......
......@@ -71,9 +71,8 @@ class ProfileTest(BaseTestCase):
self.assert_text(f'User "{username}" not found')
def test_suspended(self):
# TODO: detect suspended
self.open_nitter('test')
self.assert_text(f'User "test" not found')
self.assert_text(f'User "test" has been suspended')
@parameterized.expand(banner_color)
def test_banner_color(self, username, color):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment