mirror of https://github.com/realaravinth/gitpad
feat: DB: visibility filtered gist retrieval
SUMMARY GistDatabase::get_user_gists retrieved all gists that were created by the user. GistDatabase::get_user_public_gists and GistDatabase::get_user_public_unlisted_gists produce visibility-filtered results DESCRIPTION Gist visibility levels are ordered in the following order: --------------------------------- | Public < Unlisted < Private | --------------------------------- A user with permissions to access a visibility-level will also have access to the levels lower levels to it. Accessibility filters use this mechanism to filter gists: a higher visibility-level request will also return gists with lower visibility-levels. GistDatabase::get_user_public_unlisted_gists: Return all gists that belong to a user with public(GistVisibility::Public) and unlisted(GistVisibility::UnliUnlisted) visibility levels. Gists with private(GistVisibility::Private) visibility levels are ignored. GistDatabase::get_user_public_gists: Return all gists that belong to a user with public(GistVisibility::Public) only is returned. Private and Unlisted resources are ignored. GistDatabase::get_user_gists: Returns all gists belonging to a usermaster
parent
7cdfcc47bb
commit
06830bfd2c
|
@ -236,6 +236,13 @@ pub trait GistDatabase: std::marker::Send + std::marker::Sync + CloneGistDatabas
|
|||
/// Retrieve gists belonging to user
|
||||
async fn get_user_gists(&self, owner: &str) -> DBResult<Vec<Gist>>;
|
||||
|
||||
/// Retrieve gists belonging to user that are [GistVisibility::Public]
|
||||
async fn get_user_public_gists(&self, owner: &str) -> DBResult<Vec<Gist>>;
|
||||
|
||||
/// Retrieve gists belonging to user that are [GistVisibility::Public] and
|
||||
/// [GistVisibility::UnliUnlisted]
|
||||
async fn get_user_public_unlisted_gists(&self, owner: &str) -> DBResult<Vec<Gist>>;
|
||||
|
||||
/// Delete gist
|
||||
async fn delete_gist(&self, owner: &str, public_id: &str) -> DBResult<()>;
|
||||
|
||||
|
@ -323,6 +330,14 @@ impl GistDatabase for Box<dyn GistDatabase> {
|
|||
(**self).get_user_gists(owner).await
|
||||
}
|
||||
|
||||
async fn get_user_public_gists(&self, owner: &str) -> DBResult<Vec<Gist>> {
|
||||
(**self).get_user_public_gists(owner).await
|
||||
}
|
||||
|
||||
async fn get_user_public_unlisted_gists(&self, owner: &str) -> DBResult<Vec<Gist>> {
|
||||
(**self).get_user_public_unlisted_gists(owner).await
|
||||
}
|
||||
|
||||
async fn delete_gist(&self, owner: &str, public_id: &str) -> DBResult<()> {
|
||||
(**self).delete_gist(owner, public_id).await
|
||||
}
|
||||
|
|
|
@ -142,6 +142,49 @@ pub async fn gists_work<T: GistDatabase>(
|
|||
DBError::CommentNotFound
|
||||
));
|
||||
|
||||
// visibility filters
|
||||
let create_unlisted_gist = CreateGist {
|
||||
owner: username.into(),
|
||||
description: Some("foo"),
|
||||
public_id: &format!("{}unlisted", public_id),
|
||||
visibility: &GistVisibility::Unlisted,
|
||||
};
|
||||
db.new_gist(&create_unlisted_gist).await.unwrap();
|
||||
let create_private_gist = CreateGist {
|
||||
owner: username.into(),
|
||||
description: Some("foo"),
|
||||
public_id: &format!("{}private", public_id),
|
||||
visibility: &GistVisibility::Private,
|
||||
};
|
||||
db.new_gist(&create_private_gist).await.unwrap();
|
||||
|
||||
let public_gists = db.get_user_public_gists(username).await.unwrap();
|
||||
assert_eq!(public_gists.len(), 1);
|
||||
assert_gists(&create_gist, &public_gists[0]);
|
||||
|
||||
let public_unlisted_gists = db.get_user_public_unlisted_gists(username).await.unwrap();
|
||||
assert_eq!(public_unlisted_gists.len(), 2);
|
||||
for gist in public_unlisted_gists {
|
||||
assert_ne!(gist.visibility, GistVisibility::Private);
|
||||
if gist.visibility == GistVisibility::Public {
|
||||
assert_gists(&create_gist, &gist);
|
||||
} else {
|
||||
assert_gists(&create_unlisted_gist, &gist);
|
||||
}
|
||||
}
|
||||
|
||||
let all_gists = db.get_user_gists(username).await.unwrap();
|
||||
assert_eq!(all_gists.len(), 3);
|
||||
for gist in all_gists {
|
||||
if gist.visibility == GistVisibility::Public {
|
||||
assert_gists(&create_gist, &gist);
|
||||
} else if gist.visibility == GistVisibility::Unlisted {
|
||||
assert_gists(&create_unlisted_gist, &gist);
|
||||
} else {
|
||||
assert_gists(&create_private_gist, &gist);
|
||||
}
|
||||
}
|
||||
|
||||
// delete gist
|
||||
db.delete_gist(username, &create_gist.public_id)
|
||||
.await
|
||||
|
|
|
@ -72,6 +72,57 @@
|
|||
"nullable": []
|
||||
}
|
||||
},
|
||||
"36dec233992fb484e0ee86dac49197ddcea4e2ea47bb98a3aee89f857e13cc80": {
|
||||
"query": "SELECT\n owner,\n visibility,\n created,\n updated,\n public_id,\n description\n FROM\n gists_gists_view\n WHERE \n owner = $1\n AND\n visibility = $2\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "owner",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "visibility",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "created",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "updated",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "public_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "description",
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
}
|
||||
},
|
||||
"38409cc4e1e1edf0a5f15160d54a59b741fc668795bcdc11570e3963661c77e0": {
|
||||
"query": "SELECT\n owner,\n visibility,\n created,\n updated,\n public_id,\n description\n FROM\n gists_gists_view\n WHERE public_id = $1\n ",
|
||||
"describe": {
|
||||
|
@ -465,6 +516,57 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"f8f0c9da439206cfc4df5f916d9c4cf731c19cbf6c005a5e7f56dac5d3b90b8e": {
|
||||
"query": "SELECT\n owner,\n visibility,\n created,\n updated,\n public_id,\n description\n FROM\n gists_gists_view\n WHERE \n owner = $1\n AND\n visibility <> $2\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "owner",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "visibility",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "created",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "updated",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "public_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "description",
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
}
|
||||
},
|
||||
"fbeb7f634647d0082b9a083590b027ba668e59f2173e0699b78c2261ace2638f": {
|
||||
"query": "INSERT INTO gists_gists \n (owner_id , public_id, visibility, created, updated)\n VALUES (\n (SELECT ID FROM gists_users WHERE username = $1),\n $2, (SELECT ID FROM gists_visibility WHERE name = $3), $4, $5\n )",
|
||||
"describe": {
|
||||
|
|
|
@ -398,6 +398,78 @@ impl GistDatabase for Database {
|
|||
Ok(gists)
|
||||
}
|
||||
|
||||
/// Retrieve gists belonging to user from database
|
||||
async fn get_user_public_gists(&self, owner: &str) -> DBResult<Vec<Gist>> {
|
||||
const PUBLIC: &str = GistVisibility::Public.to_str();
|
||||
let mut res = sqlx::query_as!(
|
||||
InnerGist,
|
||||
"SELECT
|
||||
owner,
|
||||
visibility,
|
||||
created,
|
||||
updated,
|
||||
public_id,
|
||||
description
|
||||
FROM
|
||||
gists_gists_view
|
||||
WHERE
|
||||
owner = $1
|
||||
AND
|
||||
visibility = $2
|
||||
",
|
||||
owner,
|
||||
PUBLIC
|
||||
)
|
||||
.fetch_all(&self.pool)
|
||||
.await
|
||||
.map_err(|e| match e {
|
||||
Error::RowNotFound => DBError::GistNotFound,
|
||||
e => DBError::DBError(Box::new(e)),
|
||||
})?;
|
||||
|
||||
let mut gists = Vec::with_capacity(res.len());
|
||||
for r in res.drain(..) {
|
||||
gists.push(r.to_gist()?);
|
||||
}
|
||||
Ok(gists)
|
||||
}
|
||||
|
||||
/// Retrieve gists belonging to user from database
|
||||
async fn get_user_public_unlisted_gists(&self, owner: &str) -> DBResult<Vec<Gist>> {
|
||||
const PRIVATE: &str = GistVisibility::Private.to_str();
|
||||
let mut res = sqlx::query_as!(
|
||||
InnerGist,
|
||||
"SELECT
|
||||
owner,
|
||||
visibility,
|
||||
created,
|
||||
updated,
|
||||
public_id,
|
||||
description
|
||||
FROM
|
||||
gists_gists_view
|
||||
WHERE
|
||||
owner = $1
|
||||
AND
|
||||
visibility <> $2
|
||||
",
|
||||
owner,
|
||||
PRIVATE
|
||||
)
|
||||
.fetch_all(&self.pool)
|
||||
.await
|
||||
.map_err(|e| match e {
|
||||
Error::RowNotFound => DBError::GistNotFound,
|
||||
e => DBError::DBError(Box::new(e)),
|
||||
})?;
|
||||
|
||||
let mut gists = Vec::with_capacity(res.len());
|
||||
for r in res.drain(..) {
|
||||
gists.push(r.to_gist()?);
|
||||
}
|
||||
Ok(gists)
|
||||
}
|
||||
|
||||
async fn delete_gist(&self, owner: &str, public_id: &str) -> DBResult<()> {
|
||||
sqlx::query!(
|
||||
"DELETE FROM gists_gists
|
||||
|
|
|
@ -72,6 +72,54 @@
|
|||
"nullable": []
|
||||
}
|
||||
},
|
||||
"36dec233992fb484e0ee86dac49197ddcea4e2ea47bb98a3aee89f857e13cc80": {
|
||||
"query": "SELECT\n owner,\n visibility,\n created,\n updated,\n public_id,\n description\n FROM\n gists_gists_view\n WHERE \n owner = $1\n AND\n visibility = $2\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "owner",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "visibility",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "created",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "updated",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "public_id",
|
||||
"ordinal": 4,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"ordinal": 5,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
}
|
||||
},
|
||||
"38409cc4e1e1edf0a5f15160d54a59b741fc668795bcdc11570e3963661c77e0": {
|
||||
"query": "SELECT\n owner,\n visibility,\n created,\n updated,\n public_id,\n description\n FROM\n gists_gists_view\n WHERE public_id = $1\n ",
|
||||
"describe": {
|
||||
|
@ -422,6 +470,54 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"f8f0c9da439206cfc4df5f916d9c4cf731c19cbf6c005a5e7f56dac5d3b90b8e": {
|
||||
"query": "SELECT\n owner,\n visibility,\n created,\n updated,\n public_id,\n description\n FROM\n gists_gists_view\n WHERE \n owner = $1\n AND\n visibility <> $2\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "owner",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "visibility",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "created",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "updated",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "public_id",
|
||||
"ordinal": 4,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"ordinal": 5,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
}
|
||||
},
|
||||
"fbeb7f634647d0082b9a083590b027ba668e59f2173e0699b78c2261ace2638f": {
|
||||
"query": "INSERT INTO gists_gists \n (owner_id , public_id, visibility, created, updated)\n VALUES (\n (SELECT ID FROM gists_users WHERE username = $1),\n $2, (SELECT ID FROM gists_visibility WHERE name = $3), $4, $5\n )",
|
||||
"describe": {
|
||||
|
|
|
@ -361,6 +361,78 @@ impl GistDatabase for Database {
|
|||
Ok(gists)
|
||||
}
|
||||
|
||||
/// Retrieve gists belonging to user from database
|
||||
async fn get_user_public_gists(&self, owner: &str) -> DBResult<Vec<Gist>> {
|
||||
const PUBLIC: &str = GistVisibility::Public.to_str();
|
||||
let mut res = sqlx::query_as!(
|
||||
InnerGist,
|
||||
"SELECT
|
||||
owner,
|
||||
visibility,
|
||||
created,
|
||||
updated,
|
||||
public_id,
|
||||
description
|
||||
FROM
|
||||
gists_gists_view
|
||||
WHERE
|
||||
owner = $1
|
||||
AND
|
||||
visibility = $2
|
||||
",
|
||||
owner,
|
||||
PUBLIC
|
||||
)
|
||||
.fetch_all(&self.pool)
|
||||
.await
|
||||
.map_err(|e| match e {
|
||||
Error::RowNotFound => DBError::GistNotFound,
|
||||
e => DBError::DBError(Box::new(e)),
|
||||
})?;
|
||||
|
||||
let mut gists = Vec::with_capacity(res.len());
|
||||
for r in res.drain(..) {
|
||||
gists.push(r.to_gist()?);
|
||||
}
|
||||
Ok(gists)
|
||||
}
|
||||
|
||||
/// Retrieve gists belonging to user from database
|
||||
async fn get_user_public_unlisted_gists(&self, owner: &str) -> DBResult<Vec<Gist>> {
|
||||
const PRIVATE: &str = GistVisibility::Private.to_str();
|
||||
let mut res = sqlx::query_as!(
|
||||
InnerGist,
|
||||
"SELECT
|
||||
owner,
|
||||
visibility,
|
||||
created,
|
||||
updated,
|
||||
public_id,
|
||||
description
|
||||
FROM
|
||||
gists_gists_view
|
||||
WHERE
|
||||
owner = $1
|
||||
AND
|
||||
visibility <> $2
|
||||
",
|
||||
owner,
|
||||
PRIVATE
|
||||
)
|
||||
.fetch_all(&self.pool)
|
||||
.await
|
||||
.map_err(|e| match e {
|
||||
Error::RowNotFound => DBError::GistNotFound,
|
||||
e => DBError::DBError(Box::new(e)),
|
||||
})?;
|
||||
|
||||
let mut gists = Vec::with_capacity(res.len());
|
||||
for r in res.drain(..) {
|
||||
gists.push(r.to_gist()?);
|
||||
}
|
||||
Ok(gists)
|
||||
}
|
||||
|
||||
async fn delete_gist(&self, owner: &str, public_id: &str) -> DBResult<()> {
|
||||
sqlx::query!(
|
||||
"DELETE FROM gists_gists
|
||||
|
|
Loading…
Reference in New Issue