Skip to content

Commit 314016c

Browse files
committed
Add Verions Owner Actions to the API
Contributes to Issue #1548
1 parent 55fa81b commit 314016c

File tree

8 files changed

+191
-83
lines changed

8 files changed

+191
-83
lines changed

src/controllers/krate/metadata.rs

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use crate::controllers::prelude::*;
88
use crate::models::{
99
Category, Crate, CrateCategory, CrateKeyword, CrateVersions, Keyword, RecentCrateDownloads,
10-
User, Version,
10+
User, Version, VersionOwnerAction,
1111
};
1212
use crate::schema::*;
1313
use crate::views::{
@@ -105,13 +105,31 @@ pub fn show(req: &mut dyn Request) -> AppResult<Response> {
105105
let conn = req.db_conn()?;
106106
let krate = Crate::by_name(name).first::<Crate>(&*conn)?;
107107

108-
let mut versions_and_publishers: Vec<(Version, Option<User>)> = krate
108+
let mut versions_and_publishers = krate
109109
.all_versions()
110110
.left_outer_join(users::table)
111111
.select((versions::all_columns, users::all_columns.nullable()))
112-
.load(&*conn)?;
112+
.load::<(Version, Option<User>)>(&*conn)?;
113113
versions_and_publishers.sort_by(|a, b| b.0.num.cmp(&a.0.num));
114-
let ids = versions_and_publishers.iter().map(|v| v.0.id).collect();
114+
let versions = versions_and_publishers
115+
.iter()
116+
.map(|(v, _)| v)
117+
.cloned()
118+
.collect::<Vec<_>>();
119+
let audit_actions = VersionOwnerAction::belonging_to(&versions)
120+
.inner_join(users::table)
121+
.order(version_owner_actions::dsl::id)
122+
.load::<(VersionOwnerAction, User)>(&*conn)?
123+
.grouped_by(&versions);
124+
let versions_publishers_and_audit_actions = versions_and_publishers
125+
.into_iter()
126+
.zip(audit_actions.into_iter())
127+
.map(|((v, pb), aas)| (v, pb, aas))
128+
.collect::<Vec<_>>();
129+
let ids = versions_publishers_and_audit_actions
130+
.iter()
131+
.map(|v| v.0.id)
132+
.collect();
115133

116134
let kws = CrateKeyword::belonging_to(&krate)
117135
.inner_join(keywords::table)
@@ -149,9 +167,9 @@ pub fn show(req: &mut dyn Request) -> AppResult<Response> {
149167
false,
150168
recent_downloads,
151169
),
152-
versions: versions_and_publishers
170+
versions: versions_publishers_and_audit_actions
153171
.into_iter()
154-
.map(|(v, pb)| v.encodable(&krate.name, pb))
172+
.map(|(v, pb, aas)| v.encodable(&krate.name, pb, aas))
155173
.collect(),
156174
keywords: kws.into_iter().map(Keyword::encodable).collect(),
157175
categories: cats.into_iter().map(Category::encodable).collect(),
@@ -193,9 +211,20 @@ pub fn versions(req: &mut dyn Request) -> AppResult<Response> {
193211
.select((versions::all_columns, users::all_columns.nullable()))
194212
.load(&*conn)?;
195213
versions_and_publishers.sort_by(|a, b| b.0.num.cmp(&a.0.num));
214+
let versions = versions_and_publishers
215+
.iter()
216+
.map(|(v, _)| v)
217+
.cloned()
218+
.collect::<Vec<_>>();
219+
let audit_actions = VersionOwnerAction::belonging_to(&versions)
220+
.inner_join(users::table)
221+
.order(version_owner_actions::dsl::id)
222+
.load::<(VersionOwnerAction, User)>(&*conn)?
223+
.grouped_by(&versions);
196224
let versions = versions_and_publishers
197225
.into_iter()
198-
.map(|(v, pb)| v.encodable(crate_name, pb))
226+
.zip(audit_actions.into_iter())
227+
.map(|((v, pb), aas)| v.encodable(crate_name, pb, aas))
199228
.collect();
200229

201230
#[derive(Serialize)]
@@ -220,7 +249,7 @@ pub fn reverse_dependencies(req: &mut dyn Request) -> AppResult<Response> {
220249

221250
let version_ids: Vec<i32> = rev_deps.iter().map(|dep| dep.version_id).collect();
222251

223-
let versions = versions::table
252+
let versions_and_publishers = versions::table
224253
.filter(versions::id.eq(any(version_ids)))
225254
.inner_join(crates::table)
226255
.left_outer_join(users::table)
@@ -229,9 +258,23 @@ pub fn reverse_dependencies(req: &mut dyn Request) -> AppResult<Response> {
229258
crates::name,
230259
users::all_columns.nullable(),
231260
))
232-
.load::<(Version, String, Option<User>)>(&*conn)?
261+
.load::<(Version, String, Option<User>)>(&*conn)?;
262+
let versions = versions_and_publishers
263+
.iter()
264+
.map(|(v, _, _)| v)
265+
.cloned()
266+
.collect::<Vec<_>>();
267+
let audit_actions = VersionOwnerAction::belonging_to(&versions)
268+
.inner_join(users::table)
269+
.order(version_owner_actions::dsl::id)
270+
.load::<(VersionOwnerAction, User)>(&*conn)?
271+
.grouped_by(&versions);
272+
let versions = versions_and_publishers
233273
.into_iter()
234-
.map(|(version, krate_name, user)| version.encodable(&krate_name, user))
274+
.zip(audit_actions.into_iter())
275+
.map(|((version, krate_name, published_by), actions)| {
276+
version.encodable(&krate_name, published_by, actions)
277+
})
235278
.collect();
236279

237280
#[derive(Serialize)]

src/controllers/user/me.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ use crate::email;
77
use crate::util::bad_request;
88
use crate::util::errors::AppError;
99

10-
use crate::models::{CrateOwner, Email, Follow, NewEmail, OwnerKind, User, Version};
11-
use crate::schema::{crate_owners, crates, emails, follows, users, versions};
10+
use crate::models::{
11+
CrateOwner, Email, Follow, NewEmail, OwnerKind, User, Version, VersionOwnerAction,
12+
};
13+
use crate::schema::{
14+
crate_owners, crates, emails, follows, users, version_owner_actions, versions,
15+
};
1216
use crate::views::{EncodableMe, EncodableVersion, OwnedCrate};
1317

1418
/// Handles the `GET /me` route.
@@ -80,12 +84,24 @@ pub fn updates(req: &mut dyn Request) -> AppResult<Response> {
8084
))
8185
.paginate(&req.query())?
8286
.load::<(Version, String, Option<User>)>(&*conn)?;
83-
8487
let more = data.next_page_params().is_some();
88+
let versions = data.iter().map(|(v, _, _)| v).cloned().collect::<Vec<_>>();
89+
let audit_actions = VersionOwnerAction::belonging_to(&versions)
90+
.inner_join(users::table)
91+
.order(version_owner_actions::dsl::id)
92+
.load::<(VersionOwnerAction, User)>(&*conn)?
93+
.grouped_by(&versions);
94+
let data = data
95+
.into_iter()
96+
.zip(audit_actions.into_iter())
97+
.map(|((v, cn, pb), voas)| (v, cn, pb, voas))
98+
.collect::<Vec<_>>();
8599

86100
let versions = data
87101
.into_iter()
88-
.map(|(version, crate_name, published_by)| version.encodable(&crate_name, published_by))
102+
.map(|(version, crate_name, published_by, actions)| {
103+
version.encodable(&crate_name, published_by, actions)
104+
})
89105
.collect();
90106

91107
#[derive(Serialize)]
@@ -234,7 +250,7 @@ pub fn update_email_notifications(req: &mut dyn Request) -> AppResult<Response>
234250
let user = req.user()?;
235251
let conn = req.db_conn()?;
236252

237-
// Build inserts from existing crates beloning to the current user
253+
// Build inserts from existing crates belonging to the current user
238254
let to_insert = CrateOwner::by_owner_kind(OwnerKind::User)
239255
.filter(owner_id.eq(user.id))
240256
.select((crate_id, owner_id, owner_kind, email_notifications))

src/controllers/version/deprecated.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
88
use crate::controllers::prelude::*;
99

10-
use crate::models::{Crate, User, Version};
10+
use crate::models::{Crate, User, Version, VersionOwnerAction};
1111
use crate::schema::*;
1212
use crate::views::EncodableVersion;
1313

@@ -22,7 +22,7 @@ pub fn index(req: &mut dyn Request) -> AppResult<Response> {
2222
.filter_map(|(ref a, ref b)| if *a == "ids[]" { b.parse().ok() } else { None })
2323
.collect::<Vec<i32>>();
2424

25-
let versions = versions::table
25+
let versions_and_publishers = versions::table
2626
.inner_join(crates::table)
2727
.left_outer_join(users::table)
2828
.select((
@@ -31,9 +31,23 @@ pub fn index(req: &mut dyn Request) -> AppResult<Response> {
3131
users::all_columns.nullable(),
3232
))
3333
.filter(versions::id.eq(any(ids)))
34-
.load::<(Version, String, Option<User>)>(&*conn)?
34+
.load::<(Version, String, Option<User>)>(&*conn)?;
35+
let versions = versions_and_publishers
36+
.iter()
37+
.map(|(v, _, _)| v)
38+
.cloned()
39+
.collect::<Vec<_>>();
40+
let audit_actions = VersionOwnerAction::belonging_to(&versions)
41+
.inner_join(users::table)
42+
.order(version_owner_actions::dsl::id)
43+
.load::<(VersionOwnerAction, User)>(&*conn)?
44+
.grouped_by(&versions);
45+
let versions = versions_and_publishers
3546
.into_iter()
36-
.map(|(version, crate_name, published_by)| version.encodable(&crate_name, published_by))
47+
.zip(audit_actions.into_iter())
48+
.map(|((version, crate_name, published_by), actions)| {
49+
version.encodable(&crate_name, published_by, actions)
50+
})
3751
.collect();
3852

3953
#[derive(Serialize)]
@@ -60,12 +74,13 @@ pub fn show_by_id(req: &mut dyn Request) -> AppResult<Response> {
6074
users::all_columns.nullable(),
6175
))
6276
.first(&*conn)?;
77+
let audit_actions = VersionOwnerAction::by_version_id(&conn, id)?;
6378

6479
#[derive(Serialize)]
6580
struct R {
6681
version: EncodableVersion,
6782
}
6883
Ok(req.json(&R {
69-
version: version.encodable(&krate.name, published_by),
84+
version: version.encodable(&krate.name, published_by, audit_actions),
7085
}))
7186
}

src/controllers/version/metadata.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
77
use crate::controllers::prelude::*;
88

9+
use crate::models::{User, VersionOwnerAction};
910
use crate::schema::*;
1011
use crate::views::{EncodableDependency, EncodablePublicUser, EncodableVersion};
1112

@@ -70,12 +71,16 @@ pub fn show(req: &mut dyn Request) -> AppResult<Response> {
7071
let (version, krate) = version_and_crate(req)?;
7172
let conn = req.db_conn()?;
7273
let published_by = version.published_by(&conn);
74+
let actions = VersionOwnerAction::belonging_to(&version)
75+
.inner_join(users::table)
76+
.order(version_owner_actions::dsl::id)
77+
.load::<(VersionOwnerAction, User)>(&*conn)?;
7378

7479
#[derive(Serialize)]
7580
struct R {
7681
version: EncodableVersion,
7782
}
7883
Ok(req.json(&R {
79-
version: version.encodable(&krate.name, published_by),
84+
version: version.encodable(&krate.name, published_by, actions),
8085
}))
8186
}

src/models/action.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,24 @@ pub enum VersionAction {
2020
Unyank = 2,
2121
}
2222

23+
impl Into<&'static str> for VersionAction {
24+
fn into(self) -> &'static str {
25+
match self {
26+
VersionAction::Publish => "publish",
27+
VersionAction::Yank => "yank",
28+
VersionAction::Unyank => "unyank",
29+
}
30+
}
31+
}
32+
33+
impl Into<String> for VersionAction {
34+
fn into(self) -> String {
35+
let string: &'static str = self.into();
36+
37+
string.into()
38+
}
39+
}
40+
2341
impl FromSql<Integer, Pg> for VersionAction {
2442
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
2543
match <i32 as FromSql<Integer, Pg>>::from_sql(bytes)? {
@@ -56,16 +74,16 @@ impl VersionOwnerAction {
5674
version_owner_actions::table.load(conn)
5775
}
5876

59-
pub fn by_version_id_and_action(
77+
pub fn by_version_id(
6078
conn: &PgConnection,
6179
version_id_: i32,
62-
action_: VersionAction,
63-
) -> QueryResult<Vec<VersionOwnerAction>> {
64-
use version_owner_actions::dsl::{action, version_id};
80+
) -> QueryResult<Vec<(VersionOwnerAction, User)>> {
81+
use version_owner_actions::dsl::version_id;
6582

6683
version_owner_actions::table
6784
.filter(version_id.eq(version_id_))
68-
.filter(action.eq(action_))
85+
.inner_join(users::table)
86+
.order(version_owner_actions::dsl::id)
6987
.load(conn)
7088
}
7189
}

src/models/version.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use diesel::prelude::*;
55

66
use crate::util::{cargo_err, AppResult};
77

8-
use crate::models::{Crate, Dependency, User};
8+
use crate::models::{Crate, Dependency, User, VersionOwnerAction};
99
use crate::schema::*;
10-
use crate::views::{EncodableVersion, EncodableVersionLinks};
10+
use crate::views::{EncodableAuditAction, EncodableVersion, EncodableVersionLinks};
1111

1212
// Queryable has a custom implementation below
1313
#[derive(Clone, Identifiable, Associations, Debug, Queryable, Deserialize, Serialize)]
@@ -38,7 +38,12 @@ pub struct NewVersion {
3838
}
3939

4040
impl Version {
41-
pub fn encodable(self, crate_name: &str, published_by: Option<User>) -> EncodableVersion {
41+
pub fn encodable(
42+
self,
43+
crate_name: &str,
44+
published_by: Option<User>,
45+
audit_actions: Vec<(VersionOwnerAction, User)>,
46+
) -> EncodableVersion {
4247
let Version {
4348
id,
4449
num,
@@ -71,6 +76,14 @@ impl Version {
7176
},
7277
crate_size,
7378
published_by: published_by.map(User::encodable_public),
79+
audit_actions: audit_actions
80+
.into_iter()
81+
.map(|(audit_action, user)| EncodableAuditAction {
82+
action: audit_action.action.into(),
83+
user: User::encodable_public(user),
84+
time: audit_action.time,
85+
})
86+
.collect(),
7487
}
7588
}
7689

0 commit comments

Comments
 (0)