From 624036d00cda371d010a2d74733b427c4c5391bf Mon Sep 17 00:00:00 2001 From: Serhii Date: Thu, 9 Feb 2023 12:23:13 +0200 Subject: [PATCH 1/4] add address lookup for pinned tweet --- lib/entities/parse_address_from_domain.dart | 11 ++++++++--- lib/twitter/twitter_api.dart | 14 ++++++++++++-- lib/twitter/twitter_user.dart | 7 +++++-- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/lib/entities/parse_address_from_domain.dart b/lib/entities/parse_address_from_domain.dart index 6574d26fd..20ccb46c6 100644 --- a/lib/entities/parse_address_from_domain.dart +++ b/lib/entities/parse_address_from_domain.dart @@ -44,10 +44,15 @@ class AddressResolver { if (text.startsWith('@') && !text.substring(1).contains('@')) { final formattedName = text.substring(1); final twitterUser = await TwitterApi.lookupUserByName(userName: formattedName); - final address = extractAddressByType( + final addressFromBio = extractAddressByType( raw: twitterUser.description ?? '', type: CryptoCurrency.fromString(ticker)); - if (address != null) { - return ParsedAddress.fetchTwitterAddress(address: address, name: text); + final addressFromPinnedTweet = extractAddressByType( + raw: twitterUser.pinnedTweet ?? '', type: CryptoCurrency.fromString(ticker)); + if (addressFromBio != null) { + return ParsedAddress.fetchTwitterAddress(address: addressFromBio, name: text); + } + if (addressFromPinnedTweet != null) { + return ParsedAddress.fetchTwitterAddress(address: addressFromPinnedTweet, name: text); } } if (!text.startsWith('@') && text.contains('@') && !text.contains('.')) { diff --git a/lib/twitter/twitter_api.dart b/lib/twitter/twitter_api.dart index 27fb7d1a2..202e3d217 100644 --- a/lib/twitter/twitter_api.dart +++ b/lib/twitter/twitter_api.dart @@ -10,7 +10,7 @@ class TwitterApi { static const userPath = '/2/users/by/username/'; static Future lookupUserByName({required String userName}) async { - final queryParams = {'user.fields': 'description'}; + final queryParams = {'user.fields': 'description', 'expansions': 'pinned_tweet_id'}; final headers = {'authorization': 'Bearer $twitterBearerToken'}; @@ -32,6 +32,16 @@ class TwitterApi { throw Exception(responseJSON['errors'][0]['detail']); } - return TwitterUser.fromJson(responseJSON['data'] as Map); + final user = responseJSON['data'] as Map; + + try { + if (responseJSON['includes'] != null) { + user['pinnedTweet'] = responseJSON['includes']['tweets'][0]['text']; + } + } catch (e) { + print('responseJSON[includes][tweets][0][text] $e'); + } + + return TwitterUser.fromJson(user); } } diff --git a/lib/twitter/twitter_user.dart b/lib/twitter/twitter_user.dart index c4bda7859..bf5d7282a 100644 --- a/lib/twitter/twitter_user.dart +++ b/lib/twitter/twitter_user.dart @@ -1,16 +1,19 @@ class TwitterUser { - TwitterUser({required this.id, required this.username, required this.name, this.description}); + TwitterUser({required this.id, required this.username, required this.name, this.description, + this.pinnedTweet}); final String id; final String username; final String name; final String? description; + final String? pinnedTweet; factory TwitterUser.fromJson(Map json) { return TwitterUser( id: json['id'] as String, username: json['username'] as String, name: json['name'] as String, - description: json['description'] as String?); + description: json['description'] as String?, + pinnedTweet: json['pinnedTweet'] as String?); } } From 5c663c55965549ad683c525f373ddc28cab2388b Mon Sep 17 00:00:00 2001 From: Serhii Date: Mon, 13 Feb 2023 00:38:12 +0200 Subject: [PATCH 2/4] redesign user object --- lib/entities/parse_address_from_domain.dart | 19 +++-- lib/twitter/twitter_api.dart | 12 +-- lib/twitter/twitter_user.dart | 82 +++++++++++++++++---- 3 files changed, 83 insertions(+), 30 deletions(-) diff --git a/lib/entities/parse_address_from_domain.dart b/lib/entities/parse_address_from_domain.dart index 20ccb46c6..debd930cf 100644 --- a/lib/entities/parse_address_from_domain.dart +++ b/lib/entities/parse_address_from_domain.dart @@ -45,14 +45,23 @@ class AddressResolver { final formattedName = text.substring(1); final twitterUser = await TwitterApi.lookupUserByName(userName: formattedName); final addressFromBio = extractAddressByType( - raw: twitterUser.description ?? '', type: CryptoCurrency.fromString(ticker)); - final addressFromPinnedTweet = extractAddressByType( - raw: twitterUser.pinnedTweet ?? '', type: CryptoCurrency.fromString(ticker)); + raw: twitterUser.data.description, type: CryptoCurrency.fromString(ticker)); if (addressFromBio != null) { return ParsedAddress.fetchTwitterAddress(address: addressFromBio, name: text); } - if (addressFromPinnedTweet != null) { - return ParsedAddress.fetchTwitterAddress(address: addressFromPinnedTweet, name: text); + final tweets = twitterUser.includes?.tweets; + if (tweets != null) { + var subString = StringBuffer(); + tweets.forEach((item) { + subString.writeln(item.text); + }); + final userTweetsText = subString.toString(); + final addressFromPinnedTweet = + extractAddressByType(raw: userTweetsText, type: CryptoCurrency.fromString(ticker)); + + if (addressFromPinnedTweet != null) { + return ParsedAddress.fetchTwitterAddress(address: addressFromPinnedTweet, name: text); + } } } if (!text.startsWith('@') && text.contains('@') && !text.contains('.')) { diff --git a/lib/twitter/twitter_api.dart b/lib/twitter/twitter_api.dart index 202e3d217..41f5df61d 100644 --- a/lib/twitter/twitter_api.dart +++ b/lib/twitter/twitter_api.dart @@ -32,16 +32,6 @@ class TwitterApi { throw Exception(responseJSON['errors'][0]['detail']); } - final user = responseJSON['data'] as Map; - - try { - if (responseJSON['includes'] != null) { - user['pinnedTweet'] = responseJSON['includes']['tweets'][0]['text']; - } - } catch (e) { - print('responseJSON[includes][tweets][0][text] $e'); - } - - return TwitterUser.fromJson(user); + return TwitterUser.fromJson(responseJSON); } } diff --git a/lib/twitter/twitter_user.dart b/lib/twitter/twitter_user.dart index bf5d7282a..626f9cd7f 100644 --- a/lib/twitter/twitter_user.dart +++ b/lib/twitter/twitter_user.dart @@ -1,19 +1,73 @@ class TwitterUser { - TwitterUser({required this.id, required this.username, required this.name, this.description, - this.pinnedTweet}); + TwitterUser({ + required this.data, + this.includes, + }); - final String id; - final String username; - final String name; - final String? description; - final String? pinnedTweet; + late final Data data; + late final Includes? includes; - factory TwitterUser.fromJson(Map json) { - return TwitterUser( - id: json['id'] as String, - username: json['username'] as String, - name: json['name'] as String, - description: json['description'] as String?, - pinnedTweet: json['pinnedTweet'] as String?); + TwitterUser.fromJson(Map json) { + data = Data.fromJson(json['data'] as Map); + includes = json['includes'] != null + ? Includes.fromJson(json['includes'] as Map) + : null; + } +} + +class Data { + Data({ + required this.name, + required this.id, + required this.pinnedTweetId, + required this.description, + required this.username, + }); + + late final String name; + late final String id; + late final String? pinnedTweetId; + late final String description; + late final String username; + + Data.fromJson(Map json) { + name = json['name'] as String; + id = json['id'] as String; + pinnedTweetId = json['pinned_tweet_id'] as String?; + description = json['description'] as String; + username = json['username'] as String; + } +} + +class Includes { + Includes({ + required this.tweets, + }); + + late final List tweets; + + Includes.fromJson(Map json) { + tweets = List.from(json['tweets'] as Iterable) + .map((e) => Tweets.fromJson(e as Map)) + .toList(); + } +} + +class Tweets { + Tweets({ + required this.editHistoryTweetIds, + required this.id, + required this.text, + }); + + late final List editHistoryTweetIds; + late final String id; + late final String text; + + Tweets.fromJson(Map json) { + editHistoryTweetIds = + List.castFrom(json['edit_history_tweet_ids'] as List); + id = json['id'] as String; + text = json['text'] as String; } } From 7235d8c9c23872de7706cacd3d39bb9215edbc34 Mon Sep 17 00:00:00 2001 From: Serhii Date: Tue, 14 Feb 2023 00:23:57 +0200 Subject: [PATCH 3/4] redesign user object --- lib/entities/parse_address_from_domain.dart | 4 +- lib/twitter/twitter_user.dart | 92 +++++++-------------- 2 files changed, 34 insertions(+), 62 deletions(-) diff --git a/lib/entities/parse_address_from_domain.dart b/lib/entities/parse_address_from_domain.dart index debd930cf..fce9d9a56 100644 --- a/lib/entities/parse_address_from_domain.dart +++ b/lib/entities/parse_address_from_domain.dart @@ -45,11 +45,11 @@ class AddressResolver { final formattedName = text.substring(1); final twitterUser = await TwitterApi.lookupUserByName(userName: formattedName); final addressFromBio = extractAddressByType( - raw: twitterUser.data.description, type: CryptoCurrency.fromString(ticker)); + raw: twitterUser.description, type: CryptoCurrency.fromString(ticker)); if (addressFromBio != null) { return ParsedAddress.fetchTwitterAddress(address: addressFromBio, name: text); } - final tweets = twitterUser.includes?.tweets; + final tweets = twitterUser.tweets; if (tweets != null) { var subString = StringBuffer(); tweets.forEach((item) { diff --git a/lib/twitter/twitter_user.dart b/lib/twitter/twitter_user.dart index 626f9cd7f..d24a68ca0 100644 --- a/lib/twitter/twitter_user.dart +++ b/lib/twitter/twitter_user.dart @@ -1,73 +1,45 @@ class TwitterUser { - TwitterUser({ - required this.data, - this.includes, - }); + TwitterUser( + {required this.id, + required this.username, + required this.name, + required this.description, + this.tweets}); - late final Data data; - late final Includes? includes; + final String id; + final String username; + final String name; + final String description; + final List? tweets; - TwitterUser.fromJson(Map json) { - data = Data.fromJson(json['data'] as Map); - includes = json['includes'] != null - ? Includes.fromJson(json['includes'] as Map) - : null; + factory TwitterUser.fromJson(Map json) { + return TwitterUser( + id: json['data']['id'] as String, + username: json['data']['username'] as String, + name: json['data']['name'] as String, + description: json['data']['description'] as String, + tweets: json['includes'] != null + ? List.from(json['includes']['tweets'] as List) + .map((e) => Tweet.fromJson(e as Map)) + .toList() + : null, + ); } } -class Data { - Data({ - required this.name, - required this.id, - required this.pinnedTweetId, - required this.description, - required this.username, - }); - - late final String name; - late final String id; - late final String? pinnedTweetId; - late final String description; - late final String username; - - Data.fromJson(Map json) { - name = json['name'] as String; - id = json['id'] as String; - pinnedTweetId = json['pinned_tweet_id'] as String?; - description = json['description'] as String; - username = json['username'] as String; - } -} - -class Includes { - Includes({ - required this.tweets, - }); - - late final List tweets; - - Includes.fromJson(Map json) { - tweets = List.from(json['tweets'] as Iterable) - .map((e) => Tweets.fromJson(e as Map)) - .toList(); - } -} - -class Tweets { - Tweets({ - required this.editHistoryTweetIds, +class Tweet { + Tweet({ required this.id, required this.text, }); - late final List editHistoryTweetIds; - late final String id; - late final String text; + final String id; + final String text; - Tweets.fromJson(Map json) { - editHistoryTweetIds = - List.castFrom(json['edit_history_tweet_ids'] as List); - id = json['id'] as String; - text = json['text'] as String; + factory Tweet.fromJson(Map json) { + return Tweet( + id: json['id'] as String, + text: json['text'] as String, + ); } } From f77a9592b2c76e3fec32f034aee93479d4a5e62d Mon Sep 17 00:00:00 2001 From: Omar Hatem Date: Tue, 14 Feb 2023 15:17:28 +0200 Subject: [PATCH 4/4] Add nullability check on description [skip ci] --- lib/twitter/twitter_user.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/twitter/twitter_user.dart b/lib/twitter/twitter_user.dart index d24a68ca0..ac373fd62 100644 --- a/lib/twitter/twitter_user.dart +++ b/lib/twitter/twitter_user.dart @@ -17,7 +17,7 @@ class TwitterUser { id: json['data']['id'] as String, username: json['data']['username'] as String, name: json['data']['name'] as String, - description: json['data']['description'] as String, + description: json['data']['description'] as String? ?? '', tweets: json['includes'] != null ? List.from(json['includes']['tweets'] as List) .map((e) => Tweet.fromJson(e as Map))