-
Notifications
You must be signed in to change notification settings - Fork 309
login: Fetch all the data we'll want for an accounts table #55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e5d3f6a
da0cd63
88419f6
d11bd82
5551bbc
bd4eac4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import 'dart:convert'; | ||
|
||
import 'package:http/http.dart' as http; | ||
import 'package:json_annotation/json_annotation.dart'; | ||
|
||
part 'realm.g.dart'; | ||
|
||
/// https://zulip.com/api/get-server-settings | ||
/// | ||
/// Despite the name, this is really a home for certain realm-specific | ||
/// settings, as well as some information about the server as a whole. | ||
/// | ||
/// The Zulip server offers this endpoint at the root domain of a server, | ||
/// even when there is no Zulip realm at that domain. This binding, however, | ||
/// only operates on an actual Zulip realm. | ||
// TODO(#35): Perhaps detect realmless root domain, for more specific onboarding feedback. | ||
// See thread, and the zulip-mobile code and chat thread it links to: | ||
// https://github.com/zulip/zulip-flutter/pull/55#discussion_r1160267577 | ||
Future<GetServerSettingsResult> getServerSettings({ | ||
required String realmUrl, | ||
}) async { | ||
// TODO dedupe this part with LiveApiConnection; make this function testable | ||
final response = await http.get( | ||
Uri.parse("$realmUrl/api/v1/server_settings")); | ||
if (response.statusCode != 200) { | ||
throw Exception('error on GET server_settings: status ${response.statusCode}'); | ||
} | ||
final data = utf8.decode(response.bodyBytes); | ||
|
||
final json = jsonDecode(data); | ||
return GetServerSettingsResult.fromJson(json); | ||
} | ||
|
||
@JsonSerializable(fieldRename: FieldRename.snake) | ||
class GetServerSettingsResult { | ||
final Map<String, bool> authenticationMethods; | ||
// final List<ExternalAuthenticationMethod> external_authentication_methods; // TODO handle | ||
|
||
final int zulipFeatureLevel; | ||
final String zulipVersion; | ||
final String? zulipMergeBase; // TODO(server-5) | ||
|
||
final bool pushNotificationsEnabled; | ||
final bool isIncompatible; | ||
|
||
final bool emailAuthEnabled; | ||
final bool requireEmailFormatUsernames; | ||
final String realmUri; | ||
final String realmName; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
// When missing, the user requested the root domain of a Zulip server, but
// there is no realm there. User error.
//
// (Also, the server has `ROOT_DOMAIN_LANDING_PAGE = False`, the default.
// But the mobile client doesn't care about that; we just care that there
// isn't a realm at the root.)
//
// Discussion:
// https://chat.zulip.org/#narrow/stream/412-api-documentation/topic/.2Fserver_settings.3A.20.60realm_name.60.2C.20etc.2E/near/1334042
//
// TODO(server-future): Expect the error to be encoded in a proper error
// response instead of this missing property.
// TODO(server-future): Then, when all supported servers give that error,
// make this property required. and this bit of logic to handle when it's missing: if (realm_name == null) {
// See comment on realm_name in ApiResponseServerSettings.
//
// This error copies the proper error that servers *sometimes* give when
// the root domain is requested and there's no realm there. [1]
// Specifically, servers give this when
// `ROOT_DOMAIN_LANDING_PAGE = True`. That circumstance makes no
// difference to mobile.
//
// [1] Observed empirically. For details, see
// https://chat.zulip.org/#narrow/stream/412-api-documentation/topic/.2Fserver_settings.3A.20.60realm_name.60.2C.20etc.2E/near/1332900 .
throw new ApiError(400, { code: 'BAD_REQUEST', msg: 'Subdomain required', result: 'error' });
} Probably we don't need the runtime code right now, but maybe worth a comment mentioning that there's some complexity to be handled until server-future? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, my thinking was that this result type would describe only what we get when asking at an actual Zulip realm's domain, not a Zulip server's root domain when there's no realm there. I should make that explicit in dartdoc, because the https://zulip.com/api/get-server-settings doc is written with the opposite focus. When you talk to a server's root domain when no realm is there, you'll get a response that's missing several of these required fields, and so it'll throw an exception. That seems appropriate if one thinks of this as about a realm — other API endpoints don't work on such a domain either. It's basically the same as one expects if the entered URL doesn't belong to a Zulip server at all. I'll also leave a TODO comment that as part of #35 it would be good to give feedback when the user enters such a domain. I'm not sure we'll necessarily take care of that in the main round of #35 when we close that issue — in particular, I'm not aware of any existing server one can make |
||
final String realmIcon; | ||
final String realmDescription; | ||
final bool? realmWebPublicAccessEnabled; // TODO(server-5) | ||
|
||
GetServerSettingsResult({ | ||
required this.authenticationMethods, | ||
required this.zulipFeatureLevel, | ||
required this.zulipVersion, | ||
this.zulipMergeBase, | ||
required this.pushNotificationsEnabled, | ||
required this.isIncompatible, | ||
required this.emailAuthEnabled, | ||
required this.requireEmailFormatUsernames, | ||
required this.realmUri, | ||
required this.realmName, | ||
required this.realmIcon, | ||
required this.realmDescription, | ||
this.realmWebPublicAccessEnabled, | ||
}); | ||
|
||
factory GetServerSettingsResult.fromJson(Map<String, dynamic> json) => | ||
_$GetServerSettingsResultFromJson(json); | ||
|
||
Map<String, dynamic> toJson() => _$GetServerSettingsResultToJson(this); | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import 'dart:convert'; | ||
|
||
import 'package:json_annotation/json_annotation.dart'; | ||
|
||
import '../core.dart'; | ||
|
||
part 'users.g.dart'; | ||
|
||
/// https://zulip.com/api/get-own-user, abridged | ||
/// | ||
/// This route's return type is simplified because we use it only | ||
/// as a workaround on old servers. | ||
Future<GetOwnUserResult> getOwnUser(ApiConnection connection) async { | ||
final data = await connection.get('users/me', {}); | ||
return GetOwnUserResult.fromJson(jsonDecode(data)); | ||
} | ||
|
||
@JsonSerializable(fieldRename: FieldRename.snake) | ||
class GetOwnUserResult { | ||
final int userId; | ||
|
||
// There are many more properties in this route's result. | ||
// But we use this route only as a workaround on old servers: | ||
// https://github.com/zulip/zulip/issues/24980 | ||
// https://chat.zulip.org/#narrow/stream/378-api-design/topic/user.20ID.20in.20fetch-api-key/near/1540592 | ||
// for which `userId` is the only property we need. | ||
// TODO(server-7): Drop getOwnUser entirely, relying on userId from fetchApiKey. | ||
|
||
GetOwnUserResult({ | ||
required this.userId, | ||
}); | ||
|
||
factory GetOwnUserResult.fromJson(Map<String, dynamic> json) => | ||
_$GetOwnUserResultFromJson(json); | ||
|
||
Map<String, dynamic> toJson() => _$GetOwnUserResultToJson(this); | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
zulip-mobile has this comment:
// Current to FL 121.
Should we put a similar comment here? No harm in copying zulip-mobile with 121, I think, since callers don't yet use newer server features.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to use those sparingly. In general I'd prefer that the expectation is that things are up to date.
On this get-server-settings endpoint, for example, now that the current feature level is up to 171, that comment makes it look like it might be pretty stale; but in reality the last change it had (*) was at FL 116, so it's still perfectly up to date. I think most of the Zulip API is like this endpoint in that it doesn't change often, and we can pretty well keep it up to date.
The major exception is settings, which the Git history on zulip-mobile reminds me is where we first started applying this "current to" convention in zulip/zulip-mobile@3971c9c47. I think it may well make sense to use it in a couple of spots that have long lists of settings, once we add those here.
One practice we could start in order to systematically catch anything that's out of date: on each server release, take that as a prompt/reminder to go through the API changelog since the last release, find all the updates that are to API surface we describe, and apply those updates where we haven't already. Looking back at the 5.0-to-6.0 changes as an example, I think that'd be a quite manageable task.
(*) Apart from the
ignored_parameters_unsupported
thing, which is cross-cutting over the whole API and which we're not interested in anyway.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah OK, that makes sense.