wakapi/endpoints/
projects.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//! Projects endpoint.
//!
//! Ref: <https://wakatime.com/developers#projects>
//!
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

use crate::{WakapiClient, WakapiError};

use super::commit::RepositoryDetails;

/// Request parameters for the Projects endpoint.
///
/// Ref: <https://wakatime.com/developers#projects>
#[derive(Serialize, Default)]
pub struct ProjectsParams {
    /// optional - Filter projects by a search term
    q: Option<String>,
    /// optional - Page number of projects, not in documentation
    page: Option<usize>,
}

impl ProjectsParams {
    /// Create a new ProjectsParams with default values (no search term).
    pub fn new() -> ProjectsParams {
        ProjectsParams {
            q: None,
            page: None,
        }
    }

    /// Set the search term parameter for the request.
    pub fn q(mut self, q: &str) -> ProjectsParams {
        self.q = Some(q.to_string());
        self
    }

    /// Set the page parameter for the request.
    /// This will return the projects for the given page number.
    pub fn page(mut self, page: usize) -> ProjectsParams {
        self.page = Some(page);
        self
    }
}

/// Projects endpoint.
///
/// Ref: <https://wakatime.com/developers#projects>
#[derive(Deserialize, Debug)]
pub struct Projects {
    /// list of projects
    pub data: Vec<ProjectsData>,
    /// total number of projects
    pub total: usize,
    /// total number of pages
    pub total_pages: usize,
    /// current page number
    pub page: usize,
    /// previous page number
    pub prev_page: Option<usize>,
    /// next page number
    pub next_page: Option<usize>,
}

#[derive(Deserialize, Debug)]
pub struct ProjectsData {
    /// unique project id
    pub id: String,
    /// project name
    pub name: String,
    /// associated repository if connected
    pub repository: Option<RepositoryDetails>,
    /// associated project badge if enabled
    pub badge: Option<ProjectBadge>,
    /// custom project color as hex string, or null if using default color
    pub color: Option<String>,
    /// clients associated with this project
    pub clients: Vec<ProjectClients>,
    /// whether this project has a shareable url defined
    pub has_public_url: bool,
    /// time when project last received code stats as human readable string
    pub human_readable_last_heartbeat_at: String,
    /// time when project last received code stats in ISO 8601 format
    pub last_heartbeat_at: DateTime<Utc>,
    /// time when project first received code stats as human readable string; currently only set for users who signed up after 2024-02-05T00:00:00Z UTC
    pub first_heartbeat_at: Option<String>,
    /// url of this project relative to wakatime.com
    pub url: String,
    /// project name url entity encoded
    pub urlencoded_name: String,
    /// time when project was created in ISO 8601 format
    pub created_at: DateTime<Utc>,
}

#[derive(Deserialize, Debug)]
pub struct ProjectBadge {
    /// badge color
    pub color: String,
    /// badge unique id
    pub id: String,
    /// badge left text
    pub left_text: String,
    /// badge link
    pub link: String,
    /// badge project id
    pub project_id: String,
    /// badge snippets
    pub snippets: Vec<BadgeSnippet>,
    /// badge title
    pub title: String,
    /// badge url
    pub url: String,
}

#[derive(Deserialize, Debug)]
pub struct BadgeSnippet {
    /// snippet content
    pub content: String,
    /// snippet name
    pub name: String,
}

#[derive(Deserialize, Debug)]
pub struct ProjectClients {
    /// unique client id
    pub id: String,
    /// client name
    pub name: String,
    /// client rate
    pub rate: f64,
    /// client timeout
    pub timeout: usize,
}

impl Projects {
    /// Fetch the projects for the current user.
    pub fn fetch(client: &WakapiClient, params: ProjectsParams) -> Result<Self, WakapiError> {
        let url = client.build_url(
            "/api/v1/users/current/projects",
            Some(serde_url_params::to_string(&params)?),
        );
        // Debug, print url and response body
        println!(
            "url: {}\nbody: {}",
            url,
            reqwest::blocking::Client::new()
                .get(&url)
                .header("Authorization", client.get_auth_header())
                .send()?
                .text()?
        );

        let response = reqwest::blocking::Client::new()
            .get(&url)
            .header("Authorization", client.get_auth_header())
            .send()?;
        if response.status().is_success() {
            let body = response.json::<Projects>()?;
            Ok(body)
        } else {
            let error = response.json::<crate::error::ErrorMessage>()?;
            Err(WakapiError::ResponseError(error))
        }
    }
}