lockbook_shared/
api.rs

1use http::Method;
2use libsecp256k1::PublicKey;
3use serde::de::DeserializeOwned;
4use serde::{Deserialize, Serialize};
5use std::collections::{HashMap, HashSet};
6use std::fmt::Debug;
7use std::str::FromStr;
8use uuid::Uuid;
9
10use crate::account::Account;
11use crate::account::Username;
12use crate::crypto::*;
13use crate::file_metadata::{DocumentHmac, FileDiff, FileMetadata, Owner};
14use crate::server_file::ServerFile;
15use crate::signed_file::SignedFile;
16use crate::ValidationFailure;
17
18pub const FREE_TIER_USAGE_SIZE: u64 = 1000000;
19pub const PREMIUM_TIER_USAGE_SIZE: u64 = 30000000000;
20/// a fee of 1000 bytes allows 1000 file creations under the free tier.
21pub const METADATA_FEE: u64 = 1000;
22
23pub trait Request: Serialize + 'static {
24    type Response: Debug + DeserializeOwned + Clone;
25    type Error: Debug + DeserializeOwned + Clone;
26    const METHOD: Method;
27    const ROUTE: &'static str;
28}
29
30#[derive(Serialize, Deserialize, Debug, Clone)]
31pub struct RequestWrapper<T: Request> {
32    pub signed_request: ECSigned<T>,
33    pub client_version: String,
34}
35
36#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
37pub enum ErrorWrapper<E> {
38    Endpoint(E),
39    ClientUpdateRequired,
40    InvalidAuth,
41    ExpiredAuth,
42    InternalError,
43    BadRequest,
44}
45
46#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
47pub struct UpsertRequest {
48    pub updates: Vec<FileDiff<SignedFile>>,
49}
50
51impl Request for UpsertRequest {
52    type Response = ();
53    type Error = UpsertError;
54    const METHOD: Method = Method::POST;
55    const ROUTE: &'static str = "/upsert-file-metadata";
56}
57
58#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
59pub enum UpsertError {
60    /// Arises during a call to upsert, when the caller does not have the correct old version of the
61    /// File they're trying to modify
62    OldVersionIncorrect,
63
64    /// Arises during a call to upsert, when the old file is not known to the server
65    OldFileNotFound,
66
67    /// Arises during a call to upsert, when the caller suggests that a file is new, but the id already
68    /// exists
69    OldVersionRequired,
70
71    /// Arises during a call to upsert, when the person making the request is not an owner of the file
72    /// or has not signed the update
73    NotPermissioned,
74
75    /// Arises during a call to upsert, when a diff's new.id != old.id
76    DiffMalformed,
77
78    /// Metas in upsert cannot contain changes to digest
79    HmacModificationInvalid,
80
81    RootModificationInvalid,
82
83    /// Found update to a deleted file
84    DeletedFileUpdated,
85
86    /// Over the User's Tier Limit
87    UsageIsOverDataCap,
88
89    /// Other misc validation failures
90    Validation(ValidationFailure),
91}
92
93#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
94pub struct ChangeDocRequest {
95    pub diff: FileDiff<SignedFile>,
96    pub new_content: EncryptedDocument,
97}
98
99#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
100pub enum ChangeDocError {
101    HmacMissing,
102    DocumentNotFound,
103    DocumentDeleted,
104    NotPermissioned,
105    OldVersionIncorrect,
106    DiffMalformed,
107    UsageIsOverDataCap,
108}
109
110impl Request for ChangeDocRequest {
111    type Response = ();
112    type Error = ChangeDocError;
113    const METHOD: Method = Method::PUT;
114    const ROUTE: &'static str = "/change-document-content";
115}
116
117#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
118pub struct GetDocRequest {
119    pub id: Uuid,
120    pub hmac: DocumentHmac,
121}
122
123#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
124pub struct GetDocumentResponse {
125    pub content: EncryptedDocument,
126}
127
128#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
129pub enum GetDocumentError {
130    DocumentNotFound,
131    NotPermissioned,
132}
133
134impl Request for GetDocRequest {
135    type Response = GetDocumentResponse;
136    type Error = GetDocumentError;
137    const METHOD: Method = Method::GET;
138    const ROUTE: &'static str = "/get-document";
139}
140
141#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
142pub struct GetPublicKeyRequest {
143    pub username: String,
144}
145
146#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
147pub struct GetPublicKeyResponse {
148    pub key: PublicKey,
149}
150
151#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
152pub enum GetPublicKeyError {
153    InvalidUsername,
154    UserNotFound,
155}
156
157impl Request for GetPublicKeyRequest {
158    type Response = GetPublicKeyResponse;
159    type Error = GetPublicKeyError;
160    const METHOD: Method = Method::GET;
161    const ROUTE: &'static str = "/get-public-key";
162}
163
164#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
165pub struct GetUsernameRequest {
166    pub key: PublicKey,
167}
168
169#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
170pub struct GetUsernameResponse {
171    pub username: String,
172}
173
174#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
175pub enum GetUsernameError {
176    UserNotFound,
177}
178
179impl Request for GetUsernameRequest {
180    type Response = GetUsernameResponse;
181    type Error = GetUsernameError;
182    const METHOD: Method = Method::GET;
183    const ROUTE: &'static str = "/get-username";
184}
185
186#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
187pub struct GetUsageRequest {}
188
189#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
190pub struct GetUsageResponse {
191    pub usages: Vec<FileUsage>,
192    pub cap: u64,
193}
194
195impl GetUsageResponse {
196    pub fn sum_server_usage(&self) -> u64 {
197        self.usages.iter().map(|usage| usage.size_bytes).sum()
198    }
199}
200
201#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
202pub struct FileUsage {
203    pub file_id: Uuid,
204    pub size_bytes: u64,
205}
206
207#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
208pub enum GetUsageError {
209    UserNotFound,
210}
211
212impl Request for GetUsageRequest {
213    type Response = GetUsageResponse;
214    type Error = GetUsageError;
215    const METHOD: Method = Method::GET;
216    const ROUTE: &'static str = "/get-usage";
217}
218
219#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
220pub struct GetFileIdsRequest {}
221
222#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
223pub struct GetFileIdsResponse {
224    pub ids: HashSet<Uuid>,
225}
226
227#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
228pub enum GetFileIdsError {
229    UserNotFound,
230}
231
232impl Request for GetFileIdsRequest {
233    type Response = GetFileIdsResponse;
234    type Error = GetFileIdsError;
235    const METHOD: Method = Method::GET;
236    const ROUTE: &'static str = "/get-file-ids";
237}
238
239#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
240pub struct GetUpdatesRequest {
241    pub since_metadata_version: u64,
242}
243
244#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
245pub struct GetUpdatesResponse {
246    pub as_of_metadata_version: u64,
247    pub file_metadata: Vec<SignedFile>,
248}
249
250#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
251pub enum GetUpdatesError {
252    UserNotFound,
253}
254
255impl Request for GetUpdatesRequest {
256    type Response = GetUpdatesResponse;
257    type Error = GetUpdatesError;
258    const METHOD: Method = Method::GET;
259    const ROUTE: &'static str = "/get-updates";
260}
261
262#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
263pub struct NewAccountRequest {
264    pub username: Username,
265    pub public_key: PublicKey,
266    pub root_folder: SignedFile,
267}
268
269impl NewAccountRequest {
270    pub fn new(account: &Account, root_folder: &ECSigned<FileMetadata>) -> Self {
271        let root_folder = root_folder.clone();
272        NewAccountRequest {
273            username: account.username.clone(),
274            public_key: account.public_key(),
275            root_folder,
276        }
277    }
278}
279
280#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
281pub struct NewAccountResponse {
282    pub last_synced: u64,
283}
284
285#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
286pub enum NewAccountError {
287    UsernameTaken,
288    PublicKeyTaken,
289    InvalidUsername,
290    FileIdTaken,
291    Disabled,
292}
293
294impl Request for NewAccountRequest {
295    type Response = NewAccountResponse;
296    type Error = NewAccountError;
297    const METHOD: Method = Method::POST;
298    const ROUTE: &'static str = "/new-account";
299}
300
301#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
302pub struct GetBuildInfoRequest {}
303
304#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
305pub enum GetBuildInfoError {}
306
307#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
308pub struct GetBuildInfoResponse {
309    pub build_version: String,
310    pub git_commit_hash: String,
311}
312
313impl Request for GetBuildInfoRequest {
314    type Response = GetBuildInfoResponse;
315    type Error = GetBuildInfoError;
316    const METHOD: Method = Method::GET;
317    const ROUTE: &'static str = "/get-build-info";
318}
319
320#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
321pub struct DeleteAccountRequest {}
322
323#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
324pub enum DeleteAccountError {
325    UserNotFound,
326}
327
328impl Request for DeleteAccountRequest {
329    type Response = ();
330    type Error = DeleteAccountError;
331    const METHOD: Method = Method::DELETE;
332    const ROUTE: &'static str = "/delete-account";
333}
334
335#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
336pub enum PaymentMethod {
337    NewCard { number: String, exp_year: i32, exp_month: i32, cvc: String },
338    OldCard,
339}
340
341#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
342pub enum StripeAccountTier {
343    Premium(PaymentMethod),
344}
345
346#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
347pub struct UpgradeAccountStripeRequest {
348    pub account_tier: StripeAccountTier,
349}
350
351#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
352pub struct UpgradeAccountStripeResponse {}
353
354#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
355pub enum UpgradeAccountStripeError {
356    OldCardDoesNotExist,
357    AlreadyPremium,
358    CardDecline,
359    InsufficientFunds,
360    TryAgain,
361    CardNotSupported,
362    ExpiredCard,
363    InvalidCardNumber,
364    InvalidCardExpYear,
365    InvalidCardExpMonth,
366    InvalidCardCvc,
367    ExistingRequestPending,
368    UserNotFound,
369}
370
371impl Request for UpgradeAccountStripeRequest {
372    type Response = UpgradeAccountStripeResponse;
373    type Error = UpgradeAccountStripeError;
374    const METHOD: Method = Method::POST;
375    const ROUTE: &'static str = "/upgrade-account-stripe";
376}
377
378#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
379pub struct UpgradeAccountGooglePlayRequest {
380    pub purchase_token: String,
381    pub account_id: String,
382}
383
384#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
385pub struct UpgradeAccountGooglePlayResponse {}
386
387#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
388pub enum UpgradeAccountGooglePlayError {
389    AlreadyPremium,
390    InvalidPurchaseToken,
391    ExistingRequestPending,
392    UserNotFound,
393}
394
395impl Request for UpgradeAccountGooglePlayRequest {
396    type Response = UpgradeAccountGooglePlayResponse;
397    type Error = UpgradeAccountGooglePlayError;
398    const METHOD: Method = Method::POST;
399    const ROUTE: &'static str = "/upgrade-account-google-play";
400}
401
402#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
403pub struct UpgradeAccountAppStoreRequest {
404    pub original_transaction_id: String,
405    pub app_account_token: String,
406}
407
408#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
409pub struct UpgradeAccountAppStoreResponse {}
410
411#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
412pub enum UpgradeAccountAppStoreError {
413    AppStoreAccountAlreadyLinked,
414    AlreadyPremium,
415    InvalidAuthDetails,
416    ExistingRequestPending,
417    UserNotFound,
418}
419
420impl Request for UpgradeAccountAppStoreRequest {
421    type Response = UpgradeAccountAppStoreResponse;
422    type Error = UpgradeAccountAppStoreError;
423    const METHOD: Method = Method::POST;
424    const ROUTE: &'static str = "/upgrade-account-app-store";
425}
426
427#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
428pub struct CancelSubscriptionRequest {}
429
430#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
431pub struct CancelSubscriptionResponse {}
432
433#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
434pub enum CancelSubscriptionError {
435    NotPremium,
436    AlreadyCanceled,
437    UsageIsOverFreeTierDataCap,
438    UserNotFound,
439    ExistingRequestPending,
440    CannotCancelForAppStore,
441}
442
443impl Request for CancelSubscriptionRequest {
444    type Response = CancelSubscriptionResponse;
445    type Error = CancelSubscriptionError;
446    const METHOD: Method = Method::DELETE;
447    const ROUTE: &'static str = "/cancel-subscription";
448}
449
450#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
451pub struct GetSubscriptionInfoRequest {}
452
453#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
454pub struct SubscriptionInfo {
455    pub payment_platform: PaymentPlatform,
456    pub period_end: UnixTimeMillis,
457}
458
459#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
460#[serde(tag = "tag")]
461pub enum PaymentPlatform {
462    Stripe { card_last_4_digits: String },
463    GooglePlay { account_state: GooglePlayAccountState },
464    AppStore { account_state: AppStoreAccountState },
465}
466
467#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
468pub struct GetSubscriptionInfoResponse {
469    pub subscription_info: Option<SubscriptionInfo>,
470}
471
472#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
473pub enum GetSubscriptionInfoError {
474    UserNotFound,
475}
476
477impl Request for GetSubscriptionInfoRequest {
478    type Response = GetSubscriptionInfoResponse;
479    type Error = GetSubscriptionInfoError;
480    const METHOD: Method = Method::GET;
481    const ROUTE: &'static str = "/get-subscription-info";
482}
483
484#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
485pub struct AdminDisappearAccountRequest {
486    pub username: String,
487}
488
489#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
490pub enum AdminDisappearAccountError {
491    NotPermissioned,
492    UserNotFound,
493}
494
495impl Request for AdminDisappearAccountRequest {
496    type Response = ();
497    type Error = AdminDisappearAccountError;
498    const METHOD: Method = Method::DELETE;
499    const ROUTE: &'static str = "/admin-disappear-account";
500}
501
502#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
503pub struct AdminDisappearFileRequest {
504    pub id: Uuid,
505}
506
507#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
508pub enum AdminDisappearFileError {
509    NotPermissioned,
510    FileNonexistent,
511    RootModificationInvalid,
512}
513
514impl Request for AdminDisappearFileRequest {
515    type Response = ();
516    type Error = AdminDisappearFileError;
517    const METHOD: Method = Method::DELETE;
518    const ROUTE: &'static str = "/admin-disappear-file";
519}
520
521#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
522pub struct AdminValidateAccountRequest {
523    pub username: String,
524}
525
526#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)]
527pub struct AdminValidateAccount {
528    pub tree_validation_failures: Vec<ValidationFailure>,
529    pub documents_missing_size: Vec<Uuid>,
530    pub documents_missing_content: Vec<Uuid>,
531}
532
533impl AdminValidateAccount {
534    pub fn is_empty(&self) -> bool {
535        self.tree_validation_failures.is_empty()
536            && self.documents_missing_content.is_empty()
537            && self.documents_missing_size.is_empty()
538    }
539}
540
541#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
542pub enum AdminValidateAccountError {
543    NotPermissioned,
544    UserNotFound,
545}
546
547impl Request for AdminValidateAccountRequest {
548    type Response = AdminValidateAccount;
549    type Error = AdminValidateAccountError;
550    const METHOD: Method = Method::GET;
551    const ROUTE: &'static str = "/admin-validate-account";
552}
553
554#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
555pub struct AdminValidateServerRequest {}
556
557#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)]
558pub struct AdminValidateServer {
559    // accounts
560    pub users_with_validation_failures: HashMap<Username, AdminValidateAccount>,
561    // index integrity
562    pub usernames_mapped_to_wrong_accounts: HashMap<String, String>,
563    // mapped username -> account username
564    pub usernames_mapped_to_nonexistent_accounts: HashMap<String, Owner>,
565    pub usernames_unmapped_to_accounts: HashSet<String>,
566    pub owners_mapped_to_unowned_files: HashMap<Owner, HashSet<Uuid>>,
567    pub owners_mapped_to_nonexistent_files: HashMap<Owner, HashSet<Uuid>>,
568    pub owners_unmapped_to_owned_files: HashMap<Owner, HashSet<Uuid>>,
569    pub owners_unmapped: HashSet<Owner>,
570    pub sharees_mapped_to_unshared_files: HashMap<Owner, HashSet<Uuid>>,
571    pub sharees_mapped_to_nonexistent_files: HashMap<Owner, HashSet<Uuid>>,
572    pub sharees_mapped_for_owned_files: HashMap<Owner, HashSet<Uuid>>,
573    pub sharees_mapped_for_deleted_files: HashMap<Owner, HashSet<Uuid>>,
574    pub sharees_unmapped_to_shared_files: HashMap<Owner, HashSet<Uuid>>,
575    pub sharees_unmapped: HashSet<Owner>,
576    pub files_mapped_as_parent_to_non_children: HashMap<Uuid, HashSet<Uuid>>,
577    pub files_mapped_as_parent_to_nonexistent_children: HashMap<Uuid, HashSet<Uuid>>,
578    pub files_mapped_as_parent_to_self: HashSet<Uuid>,
579    pub files_unmapped_as_parent_to_children: HashMap<Uuid, HashSet<Uuid>>,
580    pub files_unmapped_as_parent: HashSet<Uuid>,
581    pub sizes_mapped_for_files_without_hmac: HashSet<Uuid>,
582    pub sizes_mapped_for_nonexistent_files: HashSet<Uuid>,
583    pub sizes_unmapped_for_files_with_hmac: HashSet<Uuid>,
584    // document presence
585    pub files_with_hmacs_and_no_contents: HashSet<Uuid>,
586}
587
588#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
589pub enum AdminValidateServerError {
590    NotPermissioned,
591}
592
593impl Request for AdminValidateServerRequest {
594    type Response = AdminValidateServer;
595    type Error = AdminValidateServerError;
596    const METHOD: Method = Method::GET;
597    const ROUTE: &'static str = "/admin-validate-server";
598}
599
600#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
601pub struct AdminListUsersRequest {
602    pub filter: Option<AccountFilter>,
603}
604
605#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
606pub enum AccountFilter {
607    Premium,
608    AppStorePremium,
609    StripePremium,
610    GooglePlayPremium,
611}
612
613#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
614pub struct AdminListUsersResponse {
615    pub users: Vec<Username>,
616}
617
618#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
619pub enum AdminListUsersError {
620    NotPermissioned,
621}
622
623impl Request for AdminListUsersRequest {
624    type Response = AdminListUsersResponse;
625    type Error = AdminListUsersError;
626    const METHOD: Method = Method::GET;
627    const ROUTE: &'static str = "/admin-list-users";
628}
629
630#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
631pub struct AdminGetAccountInfoRequest {
632    pub identifier: AccountIdentifier,
633}
634
635#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
636pub enum AccountIdentifier {
637    PublicKey(PublicKey),
638    Username(Username),
639}
640
641#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
642pub struct AdminGetAccountInfoResponse {
643    pub account: AccountInfo,
644}
645
646#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
647pub struct AccountInfo {
648    pub username: String,
649    pub root: Uuid,
650    pub payment_platform: Option<PaymentPlatform>,
651    pub usage: String,
652}
653
654#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
655pub enum AdminGetAccountInfoError {
656    UserNotFound,
657    NotPermissioned,
658}
659
660impl Request for AdminGetAccountInfoRequest {
661    type Response = AdminGetAccountInfoResponse;
662    type Error = AdminGetAccountInfoError;
663    const METHOD: Method = Method::GET;
664    const ROUTE: &'static str = "/admin-get-account-info";
665}
666
667#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
668pub struct AdminFileInfoRequest {
669    pub id: Uuid,
670}
671
672#[derive(Serialize, Deserialize, Debug, Clone)]
673pub struct AdminFileInfoResponse {
674    pub file: ServerFile,
675    pub ancestors: Vec<ServerFile>,
676    pub descendants: Vec<ServerFile>,
677}
678
679#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
680pub enum AdminFileInfoError {
681    NotPermissioned,
682    FileNonexistent,
683}
684
685impl Request for AdminFileInfoRequest {
686    type Response = AdminFileInfoResponse;
687    type Error = AdminFileInfoError;
688    const METHOD: Method = Method::GET;
689    const ROUTE: &'static str = "/admin-file-info";
690}
691
692#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
693pub enum AdminSetUserTierInfo {
694    Stripe {
695        customer_id: String,
696        customer_name: Uuid,
697        payment_method_id: String,
698        last_4: String,
699        subscription_id: String,
700        expiration_time: UnixTimeMillis,
701        account_state: StripeAccountState,
702    },
703
704    GooglePlay {
705        purchase_token: String,
706        expiration_time: UnixTimeMillis,
707        account_state: GooglePlayAccountState,
708    },
709
710    AppStore {
711        account_token: String,
712        original_transaction_id: String,
713        expiration_time: UnixTimeMillis,
714        account_state: AppStoreAccountState,
715    },
716
717    Free,
718}
719
720#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
721pub struct AdminSetUserTierRequest {
722    pub username: String,
723    pub info: AdminSetUserTierInfo,
724}
725
726#[derive(Serialize, Deserialize, Debug, Clone)]
727pub struct AdminSetUserTierResponse {}
728
729#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
730pub enum AdminSetUserTierError {
731    UserNotFound,
732    NotPermissioned,
733    ExistingRequestPending,
734}
735
736impl Request for AdminSetUserTierRequest {
737    type Response = AdminSetUserTierResponse;
738    type Error = AdminSetUserTierError;
739    const METHOD: Method = Method::POST;
740    const ROUTE: &'static str = "/admin-set-user-tier";
741}
742
743// number of milliseconds that have elapsed since the unix epoch
744pub type UnixTimeMillis = u64;
745
746#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Copy)]
747pub enum ServerIndex {
748    OwnedFiles,
749    SharedFiles,
750    FileChildren,
751}
752
753#[derive(Serialize, Deserialize, Debug, Clone)]
754pub struct AdminRebuildIndexRequest {
755    pub index: ServerIndex,
756}
757
758#[derive(Serialize, Deserialize, Debug, Clone)]
759pub enum AdminRebuildIndexError {
760    NotPermissioned,
761}
762
763impl Request for AdminRebuildIndexRequest {
764    type Response = ();
765    type Error = AdminRebuildIndexError;
766    const METHOD: Method = Method::POST;
767    const ROUTE: &'static str = "/admin-rebuild-index";
768}
769
770#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
771pub enum StripeAccountState {
772    Ok,
773    InvoiceFailed,
774    Canceled,
775}
776
777#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
778pub enum GooglePlayAccountState {
779    Ok,
780    Canceled,
781    GracePeriod,
782    OnHold,
783}
784
785#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
786pub enum AppStoreAccountState {
787    Ok,
788    GracePeriod,
789    FailedToRenew,
790    Expired,
791}
792
793impl FromStr for StripeAccountState {
794    type Err = ();
795
796    fn from_str(s: &str) -> Result<Self, Self::Err> {
797        match s {
798            "Ok" => Ok(StripeAccountState::Ok),
799            "Canceled" => Ok(StripeAccountState::Canceled),
800            "InvoiceFailed" => Ok(StripeAccountState::InvoiceFailed),
801            _ => Err(()),
802        }
803    }
804}
805
806impl FromStr for GooglePlayAccountState {
807    type Err = ();
808
809    fn from_str(s: &str) -> Result<Self, Self::Err> {
810        match s {
811            "Ok" => Ok(GooglePlayAccountState::Ok),
812            "Canceled" => Ok(GooglePlayAccountState::Canceled),
813            "GracePeriod" => Ok(GooglePlayAccountState::GracePeriod),
814            "OnHold" => Ok(GooglePlayAccountState::OnHold),
815            _ => Err(()),
816        }
817    }
818}
819
820impl FromStr for AppStoreAccountState {
821    type Err = ();
822
823    fn from_str(s: &str) -> Result<Self, Self::Err> {
824        match s {
825            "Ok" => Ok(AppStoreAccountState::Ok),
826            "Expired" => Ok(AppStoreAccountState::Expired),
827            "GracePeriod" => Ok(AppStoreAccountState::GracePeriod),
828            "FailedToRenew" => Ok(AppStoreAccountState::FailedToRenew),
829            _ => Err(()),
830        }
831    }
832}