From be2669b6e0fa4bc92376daf358daca66e32964c0 Mon Sep 17 00:00:00 2001 From: boxbeam Date: Tue, 9 Apr 2024 19:24:08 -0400 Subject: [PATCH 01/15] feat(webserver, db): Implement github provided repositories --- .../0024_github-provided-repos.down.sql | 1 + .../0024_github-provided-repos.up.sql | 9 +++ ee/tabby-db/src/github_repository_provider.rs | 58 +++++++++++++++++++ ee/tabby-db/src/lib.rs | 1 + .../src/schema/github_repository_provider.rs | 40 +++++++++++++ ee/tabby-webserver/src/schema/mod.rs | 49 +++++++++++++++- ee/tabby-webserver/src/service/dao.rs | 17 +++++- .../src/service/github_repository_provider.rs | 44 +++++++++++++- 8 files changed, 213 insertions(+), 6 deletions(-) create mode 100644 ee/tabby-db/migrations/0024_github-provided-repos.down.sql create mode 100644 ee/tabby-db/migrations/0024_github-provided-repos.up.sql diff --git a/ee/tabby-db/migrations/0024_github-provided-repos.down.sql b/ee/tabby-db/migrations/0024_github-provided-repos.down.sql new file mode 100644 index 000000000000..d2f607c5b8bd --- /dev/null +++ b/ee/tabby-db/migrations/0024_github-provided-repos.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/ee/tabby-db/migrations/0024_github-provided-repos.up.sql b/ee/tabby-db/migrations/0024_github-provided-repos.up.sql new file mode 100644 index 000000000000..e6443f774ab3 --- /dev/null +++ b/ee/tabby-db/migrations/0024_github-provided-repos.up.sql @@ -0,0 +1,9 @@ +CREATE TABLE github_provided_repositories( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + github_repository_provider_id INTEGER NOT NULL, + name TEXT NOT NULL, + git_url TEXT NOT NULL, + active BOOLEAN NOT NULL DEFAULT TRUE, + FOREIGN KEY (github_repository_provider_id) REFERENCES github_repository_provider(id), + CONSTRAINT provided_repository_unique_name UNIQUE (name) +); diff --git a/ee/tabby-db/src/github_repository_provider.rs b/ee/tabby-db/src/github_repository_provider.rs index b2741d238650..0b5f8c2de0b5 100644 --- a/ee/tabby-db/src/github_repository_provider.rs +++ b/ee/tabby-db/src/github_repository_provider.rs @@ -13,6 +13,15 @@ pub struct GithubRepositoryProviderDAO { pub access_token: Option, } +#[derive(FromRow)] +pub struct GithubProvidedRepositoryDAO { + pub id: i64, + pub github_repository_provider_id: i64, + pub name: String, + pub git_url: String, + pub active: bool, +} + impl DbConn { pub async fn create_github_provider( &self, @@ -95,4 +104,53 @@ impl DbConn { .await?; Ok(providers) } + + pub async fn create_github_provided_repository( + &self, + github_provider_id: i64, + name: String, + git_url: String, + ) -> Result<()> { + query!("INSERT INTO github_provided_repositories (github_repository_provider_id, name, git_url) VALUES (?, ?, ?)", + github_provider_id, name, git_url).execute(&self.pool).await?; + Ok(()) + } + + pub async fn delete_github_provided_repository(&self, id: i64) -> Result<()> { + let res = query!("DELETE FROM github_provided_repositories WHERE id = ?", id) + .execute(&self.pool) + .await?; + + if res.rows_affected() != 1 { + return Err(anyhow!("Repository not found")); + } + Ok(()) + } + + pub async fn list_github_provided_repositories( + &self, + provider_id: i64, + limit: Option, + skip_id: Option, + backwards: bool, + ) -> Result> { + let repos = query_paged_as!( + GithubProvidedRepositoryDAO, + "github_provided_repositories", + [ + "id", + "name", + "git_url", + "active", + "github_repository_provider_id" + ], + limit, + skip_id, + backwards, + Some(format!("github_repository_provider_id = {provider_id}")) + ) + .fetch_all(&self.pool) + .await?; + Ok(repos) + } } diff --git a/ee/tabby-db/src/lib.rs b/ee/tabby-db/src/lib.rs index d2cef167b46f..cabfac5bde56 100644 --- a/ee/tabby-db/src/lib.rs +++ b/ee/tabby-db/src/lib.rs @@ -5,6 +5,7 @@ use cache::Cache; use cached::TimedSizedCache; use chrono::{DateTime, NaiveDateTime, Utc}; pub use email_setting::EmailSettingDAO; +pub use github_repository_provider::GithubProvidedRepositoryDAO; pub use github_repository_provider::GithubRepositoryProviderDAO; pub use invitations::InvitationDAO; pub use job_runs::JobRunDAO; diff --git a/ee/tabby-webserver/src/schema/github_repository_provider.rs b/ee/tabby-webserver/src/schema/github_repository_provider.rs index 334c62e23d5c..6b5cead433f7 100644 --- a/ee/tabby-webserver/src/schema/github_repository_provider.rs +++ b/ee/tabby-webserver/src/schema/github_repository_provider.rs @@ -29,8 +29,39 @@ impl NodeType for GithubRepositoryProvider { } } +#[derive(GraphQLObject, Debug)] +#[graphql(context = Context)] +pub struct GithubProvidedRepository { + pub id: ID, + pub github_repository_provider_id: ID, + pub name: String, + pub git_url: String, +} + +impl NodeType for GithubProvidedRepository { + type Cursor = String; + + fn cursor(&self) -> Self::Cursor { + self.id.to_string() + } + + fn connection_type_name() -> &'static str { + "GithubProvidedRepositoryConnection" + } + + fn edge_type_name() -> &'static str { + "GithubProvidedRepositoryEdge" + } +} + #[async_trait] pub trait GithubRepositoryProviderService: Send + Sync { + async fn create_github_repository_provider( + &self, + display_name: String, + application_id: String, + application_secret: String, + ) -> Result; async fn get_github_repository_provider(&self, id: ID) -> Result; async fn read_github_repository_provider_secret(&self, id: ID) -> Result; async fn update_github_repository_provider_access_token( @@ -46,4 +77,13 @@ pub trait GithubRepositoryProviderService: Send + Sync { first: Option, last: Option, ) -> Result>; + + async fn list_github_provided_repositories_by_provider( + &self, + provider: ID, + after: Option, + before: Option, + first: Option, + last: Option, + ) -> Result>; } diff --git a/ee/tabby-webserver/src/schema/mod.rs b/ee/tabby-webserver/src/schema/mod.rs index a6f658f39398..f69befcfca7d 100644 --- a/ee/tabby-webserver/src/schema/mod.rs +++ b/ee/tabby-webserver/src/schema/mod.rs @@ -37,7 +37,9 @@ use self::{ RequestInvitationInput, RequestPasswordResetEmailInput, UpdateOAuthCredentialInput, }, email::{EmailService, EmailSetting, EmailSettingInput}, - github_repository_provider::{GithubRepositoryProvider, GithubRepositoryProviderService}, + github_repository_provider::{ + GithubProvidedRepository, GithubRepositoryProvider, GithubRepositoryProviderService, + }, job::JobStats, license::{IsLicenseValid, LicenseInfo, LicenseService, LicenseType}, repository::{Repository, RepositoryService}, @@ -254,6 +256,37 @@ impl Query { .await } + async fn github_provided_repositories( + ctx: &Context, + github_repository_provider_id: ID, + after: Option, + before: Option, + first: Option, + last: Option, + ) -> FieldResult> { + check_admin(ctx).await?; + relay::query_async( + after, + before, + first, + last, + |after, before, first, last| async move { + Ok(ctx + .locator + .github_repository_provider() + .list_github_provided_repositories_by_provider( + github_repository_provider_id, + after, + before, + first, + last, + ) + .await?) + }, + ) + .await + } + async fn job_runs( ctx: &Context, ids: Option>, @@ -669,6 +702,20 @@ impl Mutation { ctx.locator.license().reset_license().await?; Ok(true) } + + async fn create_github_repository_provider( + ctx: &Context, + display_name: String, + application_id: String, + application_secret: String, + ) -> Result { + check_admin(ctx).await?; + ctx.locator + .github_repository_provider() + .create_github_repository_provider(display_name, application_id, application_secret) + .await?; + Ok(true) + } } async fn check_analytic_access(ctx: &Context, users: &[ID]) -> Result<(), CoreError> { diff --git a/ee/tabby-webserver/src/service/dao.rs b/ee/tabby-webserver/src/service/dao.rs index 402e973540d3..cc517c58c3c6 100644 --- a/ee/tabby-webserver/src/service/dao.rs +++ b/ee/tabby-webserver/src/service/dao.rs @@ -2,14 +2,14 @@ use anyhow::anyhow; use hash_ids::HashIds; use lazy_static::lazy_static; use tabby_db::{ - EmailSettingDAO, GithubRepositoryProviderDAO, InvitationDAO, JobRunDAO, OAuthCredentialDAO, - RepositoryDAO, ServerSettingDAO, UserDAO, + EmailSettingDAO, GithubProvidedRepositoryDAO, GithubRepositoryProviderDAO, InvitationDAO, + JobRunDAO, OAuthCredentialDAO, RepositoryDAO, ServerSettingDAO, UserDAO, }; use crate::schema::{ auth::{self, OAuthCredential, OAuthProvider}, email::{AuthMethod, EmailSetting, Encryption}, - github_repository_provider::GithubRepositoryProvider, + github_repository_provider::{GithubProvidedRepository, GithubRepositoryProvider}, job, repository::Repository, setting::{NetworkSetting, SecuritySetting}, @@ -130,6 +130,17 @@ impl From for GithubRepositoryProvider { } } +impl From for GithubProvidedRepository { + fn from(value: GithubProvidedRepositoryDAO) -> Self { + Self { + id: value.id.as_id(), + github_repository_provider_id: value.github_repository_provider_id.as_id(), + name: value.name, + git_url: value.git_url, + } + } +} + lazy_static! { static ref HASHER: HashIds = HashIds::builder() .with_salt("tabby-id-serializer") diff --git a/ee/tabby-webserver/src/service/github_repository_provider.rs b/ee/tabby-webserver/src/service/github_repository_provider.rs index 5f4970b19443..69123f09d3d8 100644 --- a/ee/tabby-webserver/src/service/github_repository_provider.rs +++ b/ee/tabby-webserver/src/service/github_repository_provider.rs @@ -2,10 +2,12 @@ use async_trait::async_trait; use juniper::ID; use tabby_db::DbConn; -use super::AsRowid; +use super::{AsID, AsRowid}; use crate::{ schema::{ - github_repository_provider::{GithubRepositoryProvider, GithubRepositoryProviderService}, + github_repository_provider::{ + GithubProvidedRepository, GithubRepositoryProvider, GithubRepositoryProviderService, + }, Result, }, service::graphql_pagination_to_filter, @@ -21,6 +23,19 @@ pub fn new_github_repository_provider_service(db: DbConn) -> impl GithubReposito #[async_trait] impl GithubRepositoryProviderService for GithubRepositoryProviderServiceImpl { + async fn create_github_repository_provider( + &self, + display_name: String, + application_id: String, + application_secret: String, + ) -> Result { + let id = self + .db + .create_github_provider(display_name, application_id, application_secret) + .await?; + Ok(id.as_id()) + } + async fn get_github_repository_provider(&self, id: ID) -> Result { let provider = self.db.get_github_provider(id.as_rowid()?).await?; Ok(provider.into()) @@ -59,4 +74,29 @@ impl GithubRepositoryProviderService for GithubRepositoryProviderServiceImpl { .map(GithubRepositoryProvider::from) .collect()) } + + async fn list_github_provided_repositories_by_provider( + &self, + provider: ID, + after: Option, + before: Option, + first: Option, + last: Option, + ) -> Result> { + let (limit, skip_id, backwards) = graphql_pagination_to_filter(after, before, last, first)?; + let repos = self + .db + .list_github_provided_repositories( + provider.as_rowid()? as i64, + limit, + skip_id, + backwards, + ) + .await?; + + Ok(repos + .into_iter() + .map(GithubProvidedRepository::from) + .collect()) + } } From 7e831915248fd5a718acfd1fa728c6bf17ddef2a Mon Sep 17 00:00:00 2001 From: boxbeam Date: Tue, 9 Apr 2024 21:18:20 -0400 Subject: [PATCH 02/15] Split PR --- .../0024_github-provided-repos.down.sql | 2 +- .../0024_github-provided-repos.up.sql | 2 ++ ee/tabby-db/src/github_repository_provider.rs | 29 +++++++++++++++++-- ee/tabby-db/src/lib.rs | 3 +- ee/tabby-webserver/graphql/schema.graphql | 19 ++++++++++-- .../src/schema/github_repository_provider.rs | 3 ++ ee/tabby-webserver/src/schema/mod.rs | 14 ++++++++- ee/tabby-webserver/src/service/dao.rs | 1 + .../src/service/github_repository_provider.rs | 14 +++++---- 9 files changed, 73 insertions(+), 14 deletions(-) diff --git a/ee/tabby-db/migrations/0024_github-provided-repos.down.sql b/ee/tabby-db/migrations/0024_github-provided-repos.down.sql index d2f607c5b8bd..92d711019fc3 100644 --- a/ee/tabby-db/migrations/0024_github-provided-repos.down.sql +++ b/ee/tabby-db/migrations/0024_github-provided-repos.down.sql @@ -1 +1 @@ --- Add down migration script here +DROP TABLE github_provided_repositories; diff --git a/ee/tabby-db/migrations/0024_github-provided-repos.up.sql b/ee/tabby-db/migrations/0024_github-provided-repos.up.sql index e6443f774ab3..7ec9760211bd 100644 --- a/ee/tabby-db/migrations/0024_github-provided-repos.up.sql +++ b/ee/tabby-db/migrations/0024_github-provided-repos.up.sql @@ -1,6 +1,8 @@ CREATE TABLE github_provided_repositories( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, github_repository_provider_id INTEGER NOT NULL, + -- vendor_id from https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#list-repositories-for-a-user + vendor_id TEXT NOT NULL, name TEXT NOT NULL, git_url TEXT NOT NULL, active BOOLEAN NOT NULL DEFAULT TRUE, diff --git a/ee/tabby-db/src/github_repository_provider.rs b/ee/tabby-db/src/github_repository_provider.rs index 0b5f8c2de0b5..148b45e3f2d3 100644 --- a/ee/tabby-db/src/github_repository_provider.rs +++ b/ee/tabby-db/src/github_repository_provider.rs @@ -16,6 +16,7 @@ pub struct GithubRepositoryProviderDAO { #[derive(FromRow)] pub struct GithubProvidedRepositoryDAO { pub id: i64, + pub vendor_id: String, pub github_repository_provider_id: i64, pub name: String, pub git_url: String, @@ -108,11 +109,12 @@ impl DbConn { pub async fn create_github_provided_repository( &self, github_provider_id: i64, + vendor_id: String, name: String, git_url: String, ) -> Result<()> { - query!("INSERT INTO github_provided_repositories (github_repository_provider_id, name, git_url) VALUES (?, ?, ?)", - github_provider_id, name, git_url).execute(&self.pool).await?; + query!("INSERT INTO github_provided_repositories (github_repository_provider_id, vendor_id, name, git_url) VALUES (?, ?, ?, ?)", + github_provider_id, vendor_id, name, git_url).execute(&self.pool).await?; Ok(()) } @@ -139,6 +141,7 @@ impl DbConn { "github_provided_repositories", [ "id", + "vendor_id", "name", "git_url", "active", @@ -153,4 +156,26 @@ impl DbConn { .await?; Ok(repos) } + + pub async fn update_github_provided_repository_active( + &self, + id: i64, + active: bool, + ) -> Result<()> { + let not_active = !active; + let res = query!( + "UPDATE github_provided_repositories SET active = ? WHERE id = ? AND active = ?", + active, + id, + not_active + ) + .execute(&self.pool) + .await?; + + if res.rows_affected() != 1 { + return Err(anyhow!("Repository active status was not changed")); + } + + Ok(()) + } } diff --git a/ee/tabby-db/src/lib.rs b/ee/tabby-db/src/lib.rs index cabfac5bde56..47962670b1f7 100644 --- a/ee/tabby-db/src/lib.rs +++ b/ee/tabby-db/src/lib.rs @@ -5,8 +5,7 @@ use cache::Cache; use cached::TimedSizedCache; use chrono::{DateTime, NaiveDateTime, Utc}; pub use email_setting::EmailSettingDAO; -pub use github_repository_provider::GithubProvidedRepositoryDAO; -pub use github_repository_provider::GithubRepositoryProviderDAO; +pub use github_repository_provider::{GithubProvidedRepositoryDAO, GithubRepositoryProviderDAO}; pub use invitations::InvitationDAO; pub use job_runs::JobRunDAO; pub use oauth_credential::OAuthCredentialDAO; diff --git a/ee/tabby-webserver/graphql/schema.graphql b/ee/tabby-webserver/graphql/schema.graphql index d73fd88abe2d..78ed0e3f6e76 100644 --- a/ee/tabby-webserver/graphql/schema.graphql +++ b/ee/tabby-webserver/graphql/schema.graphql @@ -36,6 +36,11 @@ enum AuthMethod { LOGIN } +type GithubProvidedRepositoryConnection { + edges: [GithubProvidedRepositoryEdge!]! + pageInfo: PageInfo! +} + type RegisterResponse { accessToken: String! refreshToken: String! @@ -175,6 +180,7 @@ type Mutation { deleteEmailSetting: Boolean! uploadLicense(license: String!): Boolean! resetLicense: Boolean! + updateGithubProvidedRepositoryActive(id: ID!, active: Boolean!): Boolean! } type RepositoryEdge { @@ -192,8 +198,11 @@ type FileEntrySearchResult { indices: [Int!]! } -input NetworkSettingInput { - externalUrl: String! +type GithubProvidedRepository { + id: ID! + githubRepositoryProviderId: ID! + name: String! + gitUrl: String! } type Query { @@ -204,6 +213,7 @@ type Query { users(after: String, before: String, first: Int, last: Int): UserConnection! invitations(after: String, before: String, first: Int, last: Int): InvitationConnection! githubRepositoryProviders(after: String, before: String, first: Int, last: Int): GithubRepositoryProviderConnection! + githubProvidedRepositories(githubRepositoryProviderId: ID!, after: String, before: String, first: Int, last: Int): GithubProvidedRepositoryConnection! jobRuns(ids: [ID!], jobs: [String!], after: String, before: String, first: Int, last: Int): JobRunConnection! jobRunStats(jobs: [String!]): JobStats! emailSetting: EmailSetting @@ -328,6 +338,11 @@ type PageInfo { endCursor: String } +type GithubProvidedRepositoryEdge { + node: GithubProvidedRepository! + cursor: String! +} + type Repository { id: ID! name: String! diff --git a/ee/tabby-webserver/src/schema/github_repository_provider.rs b/ee/tabby-webserver/src/schema/github_repository_provider.rs index 6b5cead433f7..040c03e61221 100644 --- a/ee/tabby-webserver/src/schema/github_repository_provider.rs +++ b/ee/tabby-webserver/src/schema/github_repository_provider.rs @@ -33,6 +33,7 @@ impl NodeType for GithubRepositoryProvider { #[graphql(context = Context)] pub struct GithubProvidedRepository { pub id: ID, + pub vendor_id: String, pub github_repository_provider_id: ID, pub name: String, pub git_url: String, @@ -86,4 +87,6 @@ pub trait GithubRepositoryProviderService: Send + Sync { first: Option, last: Option, ) -> Result>; + + async fn update_github_provided_repository_active(&self, id: ID, active: bool) -> Result<()>; } diff --git a/ee/tabby-webserver/src/schema/mod.rs b/ee/tabby-webserver/src/schema/mod.rs index f69befcfca7d..f28cb475df67 100644 --- a/ee/tabby-webserver/src/schema/mod.rs +++ b/ee/tabby-webserver/src/schema/mod.rs @@ -256,7 +256,7 @@ impl Query { .await } - async fn github_provided_repositories( + async fn github_repositories_by_provider( ctx: &Context, github_repository_provider_id: ID, after: Option, @@ -716,6 +716,18 @@ impl Mutation { .await?; Ok(true) } + + async fn update_github_provided_repository_active( + ctx: &Context, + id: ID, + active: bool, + ) -> Result { + ctx.locator + .github_repository_provider() + .update_github_provided_repository_active(id, active) + .await?; + Ok(true) + } } async fn check_analytic_access(ctx: &Context, users: &[ID]) -> Result<(), CoreError> { diff --git a/ee/tabby-webserver/src/service/dao.rs b/ee/tabby-webserver/src/service/dao.rs index cc517c58c3c6..91bdbb305084 100644 --- a/ee/tabby-webserver/src/service/dao.rs +++ b/ee/tabby-webserver/src/service/dao.rs @@ -137,6 +137,7 @@ impl From for GithubProvidedRepository { github_repository_provider_id: value.github_repository_provider_id.as_id(), name: value.name, git_url: value.git_url, + vendor_id: value.vendor_id, } } } diff --git a/ee/tabby-webserver/src/service/github_repository_provider.rs b/ee/tabby-webserver/src/service/github_repository_provider.rs index 69123f09d3d8..122ffec727a2 100644 --- a/ee/tabby-webserver/src/service/github_repository_provider.rs +++ b/ee/tabby-webserver/src/service/github_repository_provider.rs @@ -86,12 +86,7 @@ impl GithubRepositoryProviderService for GithubRepositoryProviderServiceImpl { let (limit, skip_id, backwards) = graphql_pagination_to_filter(after, before, last, first)?; let repos = self .db - .list_github_provided_repositories( - provider.as_rowid()? as i64, - limit, - skip_id, - backwards, - ) + .list_github_provided_repositories(provider.as_rowid()?, limit, skip_id, backwards) .await?; Ok(repos @@ -99,4 +94,11 @@ impl GithubRepositoryProviderService for GithubRepositoryProviderServiceImpl { .map(GithubProvidedRepository::from) .collect()) } + + async fn update_github_provided_repository_active(&self, id: ID, active: bool) -> Result<()> { + self.db + .update_github_provided_repository_active(id.as_rowid()?, active) + .await?; + Ok(()) + } } From 6a590231241bbc3a108ab762affc289abde4c21b Mon Sep 17 00:00:00 2001 From: boxbeam Date: Tue, 9 Apr 2024 22:52:43 -0400 Subject: [PATCH 03/15] Implement suggestions and RepositoryAccess listing github-provided repos --- .../0024_github-provided-repos.up.sql | 5 +- ee/tabby-db/src/github_repository_provider.rs | 10 ++- ee/tabby-webserver/src/hub/mod.rs | 76 ++++++++++++++++++- .../src/schema/github_repository_provider.rs | 4 +- ee/tabby-webserver/src/schema/mod.rs | 6 +- ee/tabby-webserver/src/service/dao.rs | 1 + .../src/service/github_repository_provider.rs | 17 ++++- 7 files changed, 106 insertions(+), 13 deletions(-) diff --git a/ee/tabby-db/migrations/0024_github-provided-repos.up.sql b/ee/tabby-db/migrations/0024_github-provided-repos.up.sql index 7ec9760211bd..dc11e6c1f8d0 100644 --- a/ee/tabby-db/migrations/0024_github-provided-repos.up.sql +++ b/ee/tabby-db/migrations/0024_github-provided-repos.up.sql @@ -5,7 +5,6 @@ CREATE TABLE github_provided_repositories( vendor_id TEXT NOT NULL, name TEXT NOT NULL, git_url TEXT NOT NULL, - active BOOLEAN NOT NULL DEFAULT TRUE, - FOREIGN KEY (github_repository_provider_id) REFERENCES github_repository_provider(id), - CONSTRAINT provided_repository_unique_name UNIQUE (name) + active BOOLEAN NOT NULL DEFAULT FALSE, + FOREIGN KEY (github_repository_provider_id) REFERENCES github_repository_provider(id) ON DELETE CASCADE ); diff --git a/ee/tabby-db/src/github_repository_provider.rs b/ee/tabby-db/src/github_repository_provider.rs index 148b45e3f2d3..3efa0bcd2eac 100644 --- a/ee/tabby-db/src/github_repository_provider.rs +++ b/ee/tabby-db/src/github_repository_provider.rs @@ -131,11 +131,16 @@ impl DbConn { pub async fn list_github_provided_repositories( &self, - provider_id: i64, + provider_ids: Vec, limit: Option, skip_id: Option, backwards: bool, ) -> Result> { + let provider_ids = provider_ids + .into_iter() + .map(|id| id.to_string()) + .collect::>() + .join(", "); let repos = query_paged_as!( GithubProvidedRepositoryDAO, "github_provided_repositories", @@ -150,7 +155,8 @@ impl DbConn { limit, skip_id, backwards, - Some(format!("github_repository_provider_id = {provider_id}")) + (!provider_ids.is_empty()) + .then(|| format!("github_repository_provider_id IN ({provider_ids})")) ) .fetch_all(&self.pool) .await?; diff --git a/ee/tabby-webserver/src/hub/mod.rs b/ee/tabby-webserver/src/hub/mod.rs index f09dea180289..0281736201af 100644 --- a/ee/tabby-webserver/src/hub/mod.rs +++ b/ee/tabby-webserver/src/hub/mod.rs @@ -145,7 +145,10 @@ impl Hub for Arc { } } } + async fn list_repositories(self, _context: tarpc::context::Context) -> Vec { + let mut repositories = vec![]; + let result = self .ctx .repository() @@ -157,9 +160,78 @@ impl Hub for Arc { .map(|r| RepositoryConfig::new_named(r.name, r.git_url)) .collect() }); - result.unwrap_or_else(|e| { + repositories.extend(result.unwrap_or_else(|e| { warn!("Failed to fetch repositories: {e}"); vec![] - }) + })); + + let provider_service = self.ctx.github_repository_provider(); + let repository_providers = provider_service + .list_github_repository_providers(None, None, Some(1024), None) + .await + .unwrap_or_else(|e| { + warn!("Failed to fetch GitHub repository providers: {e}"); + vec![] + }); + + for provider in repository_providers { + let Ok(access_token) = provider_service + .read_github_repository_provider_access_token(provider.id.clone()) + .await + else { + continue; + }; + + let repos = match provider_service + .list_github_provided_repositories_by_provider( + vec![provider.id.clone()], + None, + None, + Some(1024), + None, + ) + .await + { + Ok(repos) => repos, + Err(e) => { + warn!( + "Failed to retrieve repositories provided by {name}: {e}", + name = provider.display_name + ); + continue; + } + }; + repositories.extend(repos.into_iter().filter(|repo| repo.active).map(|repo| { + RepositoryConfig::new_named( + repo.name, + format_authenticated_git_url(repo.git_url, &access_token), + ) + })) + } + + repositories + } +} + +fn format_authenticated_git_url(mut git_url: String, access_token: &str) -> String { + let split_pos = git_url.find("://").map(|i| i + 3).unwrap_or(0); + git_url.insert_str(split_pos, &format!("{access_token}@")); + git_url +} + +#[cfg(test)] +mod tests { + use crate::hub::format_authenticated_git_url; + + #[test] + fn test_format_authenticated_git_url() { + assert_eq!( + format_authenticated_git_url("https://github.com/TabbyML/tabby".into(), "token".into()), + "https://token@github.com/TabbyML/tabby" + ); + assert_eq!( + format_authenticated_git_url("github.com/TabbyML/tabby".into(), "token".into()), + "token@github.com/TabbyML/tabby" + ); } } diff --git a/ee/tabby-webserver/src/schema/github_repository_provider.rs b/ee/tabby-webserver/src/schema/github_repository_provider.rs index 040c03e61221..a65dd3cb0098 100644 --- a/ee/tabby-webserver/src/schema/github_repository_provider.rs +++ b/ee/tabby-webserver/src/schema/github_repository_provider.rs @@ -37,6 +37,7 @@ pub struct GithubProvidedRepository { pub github_repository_provider_id: ID, pub name: String, pub git_url: String, + pub active: bool, } impl NodeType for GithubProvidedRepository { @@ -65,6 +66,7 @@ pub trait GithubRepositoryProviderService: Send + Sync { ) -> Result; async fn get_github_repository_provider(&self, id: ID) -> Result; async fn read_github_repository_provider_secret(&self, id: ID) -> Result; + async fn read_github_repository_provider_access_token(&self, id: ID) -> Result; async fn update_github_repository_provider_access_token( &self, id: ID, @@ -81,7 +83,7 @@ pub trait GithubRepositoryProviderService: Send + Sync { async fn list_github_provided_repositories_by_provider( &self, - provider: ID, + provider: Vec, after: Option, before: Option, first: Option, diff --git a/ee/tabby-webserver/src/schema/mod.rs b/ee/tabby-webserver/src/schema/mod.rs index f28cb475df67..d4316ff70fad 100644 --- a/ee/tabby-webserver/src/schema/mod.rs +++ b/ee/tabby-webserver/src/schema/mod.rs @@ -256,9 +256,9 @@ impl Query { .await } - async fn github_repositories_by_provider( + async fn github_repositories( ctx: &Context, - github_repository_provider_id: ID, + provider_ids: Vec, after: Option, before: Option, first: Option, @@ -275,7 +275,7 @@ impl Query { .locator .github_repository_provider() .list_github_provided_repositories_by_provider( - github_repository_provider_id, + provider_ids, after, before, first, diff --git a/ee/tabby-webserver/src/service/dao.rs b/ee/tabby-webserver/src/service/dao.rs index 91bdbb305084..08542cf39d2b 100644 --- a/ee/tabby-webserver/src/service/dao.rs +++ b/ee/tabby-webserver/src/service/dao.rs @@ -138,6 +138,7 @@ impl From for GithubProvidedRepository { name: value.name, git_url: value.git_url, vendor_id: value.vendor_id, + active: value.active, } } } diff --git a/ee/tabby-webserver/src/service/github_repository_provider.rs b/ee/tabby-webserver/src/service/github_repository_provider.rs index 122ffec727a2..1c9bf110b3b7 100644 --- a/ee/tabby-webserver/src/service/github_repository_provider.rs +++ b/ee/tabby-webserver/src/service/github_repository_provider.rs @@ -1,3 +1,4 @@ +use anyhow::anyhow; use async_trait::async_trait; use juniper::ID; use tabby_db::DbConn; @@ -46,6 +47,14 @@ impl GithubRepositoryProviderService for GithubRepositoryProviderServiceImpl { Ok(provider.secret) } + async fn read_github_repository_provider_access_token(&self, id: ID) -> Result { + let provider = self.db.get_github_provider(id.as_rowid()?).await?; + let Some(access_token) = provider.access_token else { + return Err(anyhow!("Provider has no access token").into()); + }; + Ok(access_token) + } + async fn update_github_repository_provider_access_token( &self, id: ID, @@ -77,16 +86,20 @@ impl GithubRepositoryProviderService for GithubRepositoryProviderServiceImpl { async fn list_github_provided_repositories_by_provider( &self, - provider: ID, + providers: Vec, after: Option, before: Option, first: Option, last: Option, ) -> Result> { + let providers = providers + .into_iter() + .map(|i| i.as_rowid()) + .collect::, _>>()?; let (limit, skip_id, backwards) = graphql_pagination_to_filter(after, before, last, first)?; let repos = self .db - .list_github_provided_repositories(provider.as_rowid()?, limit, skip_id, backwards) + .list_github_provided_repositories(providers, limit, skip_id, backwards) .await?; Ok(repos From f2ecece48f56b476819c6a9cb80ed763f0f5bb5e Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 10 Apr 2024 02:59:45 +0000 Subject: [PATCH 04/15] [autofix.ci] apply automated fixes --- ee/tabby-webserver/graphql/schema.graphql | 9 ++++++++- ee/tabby-webserver/src/hub/mod.rs | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/ee/tabby-webserver/graphql/schema.graphql b/ee/tabby-webserver/graphql/schema.graphql index 78ed0e3f6e76..dd89efed10f2 100644 --- a/ee/tabby-webserver/graphql/schema.graphql +++ b/ee/tabby-webserver/graphql/schema.graphql @@ -180,6 +180,7 @@ type Mutation { deleteEmailSetting: Boolean! uploadLicense(license: String!): Boolean! resetLicense: Boolean! + createGithubRepositoryProvider(displayName: String!, applicationId: String!, applicationSecret: String!): Boolean! updateGithubProvidedRepositoryActive(id: ID!, active: Boolean!): Boolean! } @@ -200,9 +201,11 @@ type FileEntrySearchResult { type GithubProvidedRepository { id: ID! + vendorId: String! githubRepositoryProviderId: ID! name: String! gitUrl: String! + active: Boolean! } type Query { @@ -213,7 +216,7 @@ type Query { users(after: String, before: String, first: Int, last: Int): UserConnection! invitations(after: String, before: String, first: Int, last: Int): InvitationConnection! githubRepositoryProviders(after: String, before: String, first: Int, last: Int): GithubRepositoryProviderConnection! - githubProvidedRepositories(githubRepositoryProviderId: ID!, after: String, before: String, first: Int, last: Int): GithubProvidedRepositoryConnection! + githubRepositories(providerIds: [ID!]!, after: String, before: String, first: Int, last: Int): GithubProvidedRepositoryConnection! jobRuns(ids: [ID!], jobs: [String!], after: String, before: String, first: Int, last: Int): JobRunConnection! jobRunStats(jobs: [String!]): JobStats! emailSetting: EmailSetting @@ -231,6 +234,10 @@ type Query { dailyStats(start: DateTimeUtc!, end: DateTimeUtc!, users: [ID!], languages: [Language!]): [CompletionStats!]! } +input NetworkSettingInput { + externalUrl: String! +} + enum Encryption { START_TLS SSL_TLS diff --git a/ee/tabby-webserver/src/hub/mod.rs b/ee/tabby-webserver/src/hub/mod.rs index 0281736201af..a56bc7200726 100644 --- a/ee/tabby-webserver/src/hub/mod.rs +++ b/ee/tabby-webserver/src/hub/mod.rs @@ -226,11 +226,11 @@ mod tests { #[test] fn test_format_authenticated_git_url() { assert_eq!( - format_authenticated_git_url("https://github.com/TabbyML/tabby".into(), "token".into()), + format_authenticated_git_url("https://github.com/TabbyML/tabby".into(), "token"), "https://token@github.com/TabbyML/tabby" ); assert_eq!( - format_authenticated_git_url("github.com/TabbyML/tabby".into(), "token".into()), + format_authenticated_git_url("github.com/TabbyML/tabby".into(), "token"), "token@github.com/TabbyML/tabby" ); } From 5a3d0045d601c23e09393e35bbacb31c3c1aa972 Mon Sep 17 00:00:00 2001 From: boxbeam Date: Tue, 9 Apr 2024 23:06:02 -0400 Subject: [PATCH 05/15] Finish splitting PRs --- .../src/schema/github_repository_provider.rs | 6 ------ ee/tabby-webserver/src/schema/mod.rs | 14 -------------- .../src/service/github_repository_provider.rs | 15 +-------------- 3 files changed, 1 insertion(+), 34 deletions(-) diff --git a/ee/tabby-webserver/src/schema/github_repository_provider.rs b/ee/tabby-webserver/src/schema/github_repository_provider.rs index a65dd3cb0098..68989ddeadcd 100644 --- a/ee/tabby-webserver/src/schema/github_repository_provider.rs +++ b/ee/tabby-webserver/src/schema/github_repository_provider.rs @@ -58,12 +58,6 @@ impl NodeType for GithubProvidedRepository { #[async_trait] pub trait GithubRepositoryProviderService: Send + Sync { - async fn create_github_repository_provider( - &self, - display_name: String, - application_id: String, - application_secret: String, - ) -> Result; async fn get_github_repository_provider(&self, id: ID) -> Result; async fn read_github_repository_provider_secret(&self, id: ID) -> Result; async fn read_github_repository_provider_access_token(&self, id: ID) -> Result; diff --git a/ee/tabby-webserver/src/schema/mod.rs b/ee/tabby-webserver/src/schema/mod.rs index d4316ff70fad..49fbb3bcbb5b 100644 --- a/ee/tabby-webserver/src/schema/mod.rs +++ b/ee/tabby-webserver/src/schema/mod.rs @@ -703,20 +703,6 @@ impl Mutation { Ok(true) } - async fn create_github_repository_provider( - ctx: &Context, - display_name: String, - application_id: String, - application_secret: String, - ) -> Result { - check_admin(ctx).await?; - ctx.locator - .github_repository_provider() - .create_github_repository_provider(display_name, application_id, application_secret) - .await?; - Ok(true) - } - async fn update_github_provided_repository_active( ctx: &Context, id: ID, diff --git a/ee/tabby-webserver/src/service/github_repository_provider.rs b/ee/tabby-webserver/src/service/github_repository_provider.rs index 1c9bf110b3b7..e99cb4ee90da 100644 --- a/ee/tabby-webserver/src/service/github_repository_provider.rs +++ b/ee/tabby-webserver/src/service/github_repository_provider.rs @@ -3,7 +3,7 @@ use async_trait::async_trait; use juniper::ID; use tabby_db::DbConn; -use super::{AsID, AsRowid}; +use super::AsRowid; use crate::{ schema::{ github_repository_provider::{ @@ -24,19 +24,6 @@ pub fn new_github_repository_provider_service(db: DbConn) -> impl GithubReposito #[async_trait] impl GithubRepositoryProviderService for GithubRepositoryProviderServiceImpl { - async fn create_github_repository_provider( - &self, - display_name: String, - application_id: String, - application_secret: String, - ) -> Result { - let id = self - .db - .create_github_provider(display_name, application_id, application_secret) - .await?; - Ok(id.as_id()) - } - async fn get_github_repository_provider(&self, id: ID) -> Result { let provider = self.db.get_github_provider(id.as_rowid()?).await?; Ok(provider.into()) From beee7190fbacf4e92a000651a0ea2c476e749fbf Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 10 Apr 2024 03:15:12 +0000 Subject: [PATCH 06/15] [autofix.ci] apply automated fixes --- ee/tabby-webserver/graphql/schema.graphql | 1 - 1 file changed, 1 deletion(-) diff --git a/ee/tabby-webserver/graphql/schema.graphql b/ee/tabby-webserver/graphql/schema.graphql index dd89efed10f2..b3f81884c1f7 100644 --- a/ee/tabby-webserver/graphql/schema.graphql +++ b/ee/tabby-webserver/graphql/schema.graphql @@ -180,7 +180,6 @@ type Mutation { deleteEmailSetting: Boolean! uploadLicense(license: String!): Boolean! resetLicense: Boolean! - createGithubRepositoryProvider(displayName: String!, applicationId: String!, applicationSecret: String!): Boolean! updateGithubProvidedRepositoryActive(id: ID!, active: Boolean!): Boolean! } From 4cc8ec02280087482732595888565e48b03fc8f6 Mon Sep 17 00:00:00 2001 From: boxbeam Date: Wed, 10 Apr 2024 13:02:12 -0400 Subject: [PATCH 07/15] Apply suggestion, add back authentication middleware --- ee/tabby-webserver/src/handler.rs | 6 +++++- ee/tabby-webserver/src/hub/mod.rs | 4 ++-- ee/tabby-webserver/src/integrations/github.rs | 11 +++++++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/ee/tabby-webserver/src/handler.rs b/ee/tabby-webserver/src/handler.rs index c1c51a44712d..49c2cec1ff26 100644 --- a/ee/tabby-webserver/src/handler.rs +++ b/ee/tabby-webserver/src/handler.rs @@ -144,7 +144,11 @@ impl WebserverHandle { ) .nest( "/integrations/github", - integrations::github::routes(ctx.setting(), ctx.github_repository_provider()), + integrations::github::routes( + ctx.auth(), + ctx.setting(), + ctx.github_repository_provider(), + ), ) .route( "/avatar/:id", diff --git a/ee/tabby-webserver/src/hub/mod.rs b/ee/tabby-webserver/src/hub/mod.rs index a56bc7200726..572712f68d74 100644 --- a/ee/tabby-webserver/src/hub/mod.rs +++ b/ee/tabby-webserver/src/hub/mod.rs @@ -167,7 +167,7 @@ impl Hub for Arc { let provider_service = self.ctx.github_repository_provider(); let repository_providers = provider_service - .list_github_repository_providers(None, None, Some(1024), None) + .list_github_repository_providers(None, None, None, None) .await .unwrap_or_else(|e| { warn!("Failed to fetch GitHub repository providers: {e}"); @@ -187,7 +187,7 @@ impl Hub for Arc { vec![provider.id.clone()], None, None, - Some(1024), + None, None, ) .await diff --git a/ee/tabby-webserver/src/integrations/github.rs b/ee/tabby-webserver/src/integrations/github.rs index af70237253c8..2b2b84e77a68 100644 --- a/ee/tabby-webserver/src/integrations/github.rs +++ b/ee/tabby-webserver/src/integrations/github.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use anyhow::Result; use axum::{ extract::{Path, Query, State}, + middleware::from_fn_with_state, response::Redirect, routing, Router, }; @@ -12,8 +13,12 @@ use serde::Deserialize; use tracing::error; use url::Url; -use crate::schema::{ - github_repository_provider::GithubRepositoryProviderService, setting::SettingService, +use crate::{ + handler::require_login_middleware, + schema::{ + auth::AuthenticationService, github_repository_provider::GithubRepositoryProviderService, + setting::SettingService, + }, }; #[derive(Debug, Deserialize)] @@ -47,6 +52,7 @@ struct IntegrationState { } pub fn routes( + auth: Arc, settings: Arc, github_repository_provider: Arc, ) -> Router { @@ -57,6 +63,7 @@ pub fn routes( Router::new() .route("/connect/:id", routing::get(connect)) .route("/callback", routing::get(callback)) + .layer(from_fn_with_state(auth, require_login_middleware)) .with_state(state) } From c9659add7def400c7b6a4c501bfd60f6161145e3 Mon Sep 17 00:00:00 2001 From: boxbeam Date: Mon, 15 Apr 2024 14:33:58 -0400 Subject: [PATCH 08/15] Revert RepositoryAccess changes --- ee/tabby-webserver/src/hub/mod.rs | 76 +------------------------------ 1 file changed, 2 insertions(+), 74 deletions(-) diff --git a/ee/tabby-webserver/src/hub/mod.rs b/ee/tabby-webserver/src/hub/mod.rs index 572712f68d74..f09dea180289 100644 --- a/ee/tabby-webserver/src/hub/mod.rs +++ b/ee/tabby-webserver/src/hub/mod.rs @@ -145,10 +145,7 @@ impl Hub for Arc { } } } - async fn list_repositories(self, _context: tarpc::context::Context) -> Vec { - let mut repositories = vec![]; - let result = self .ctx .repository() @@ -160,78 +157,9 @@ impl Hub for Arc { .map(|r| RepositoryConfig::new_named(r.name, r.git_url)) .collect() }); - repositories.extend(result.unwrap_or_else(|e| { + result.unwrap_or_else(|e| { warn!("Failed to fetch repositories: {e}"); vec![] - })); - - let provider_service = self.ctx.github_repository_provider(); - let repository_providers = provider_service - .list_github_repository_providers(None, None, None, None) - .await - .unwrap_or_else(|e| { - warn!("Failed to fetch GitHub repository providers: {e}"); - vec![] - }); - - for provider in repository_providers { - let Ok(access_token) = provider_service - .read_github_repository_provider_access_token(provider.id.clone()) - .await - else { - continue; - }; - - let repos = match provider_service - .list_github_provided_repositories_by_provider( - vec![provider.id.clone()], - None, - None, - None, - None, - ) - .await - { - Ok(repos) => repos, - Err(e) => { - warn!( - "Failed to retrieve repositories provided by {name}: {e}", - name = provider.display_name - ); - continue; - } - }; - repositories.extend(repos.into_iter().filter(|repo| repo.active).map(|repo| { - RepositoryConfig::new_named( - repo.name, - format_authenticated_git_url(repo.git_url, &access_token), - ) - })) - } - - repositories - } -} - -fn format_authenticated_git_url(mut git_url: String, access_token: &str) -> String { - let split_pos = git_url.find("://").map(|i| i + 3).unwrap_or(0); - git_url.insert_str(split_pos, &format!("{access_token}@")); - git_url -} - -#[cfg(test)] -mod tests { - use crate::hub::format_authenticated_git_url; - - #[test] - fn test_format_authenticated_git_url() { - assert_eq!( - format_authenticated_git_url("https://github.com/TabbyML/tabby".into(), "token"), - "https://token@github.com/TabbyML/tabby" - ); - assert_eq!( - format_authenticated_git_url("github.com/TabbyML/tabby".into(), "token"), - "token@github.com/TabbyML/tabby" - ); + }) } } From bd71d56dfa12d0f47801a8d37d499dc2e15a1392 Mon Sep 17 00:00:00 2001 From: boxbeam Date: Mon, 15 Apr 2024 14:34:58 -0400 Subject: [PATCH 09/15] Update schema after rebasing --- ee/tabby-db/schema.sqlite | Bin 143360 -> 147456 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ee/tabby-db/schema.sqlite b/ee/tabby-db/schema.sqlite index 7424ba93c65c9be83c38fc0cd3ad0f8e044082e6..75e988b6a4d42f4ff0f22d258980bbb90332fcd7 100644 GIT binary patch delta 1214 zcmZp8z|qjaIYC;GiGhJZ1&Colexi;sBh$u&`TQIryg)$-wo{YY1@xKNPHlD+n8cQv zEWyrbZp@j(ERmjBl2MwZTTql=mYI^8qFa<&kY8+MU}U0eV4`bis$ghgWo%+)Y}8^M zxr$3SqZO%;Wj3~MO?)-&-Qs0Q5xE0;sDa*50@Cn>3dH0kW%GB zm@v6q%78gy?#s!mq!f{buL6a`UiwYukXAqzHj*}A4!`wla;mfuvhYHnaLkGmldnjl zn9VE$R2}I)*-Qq->_nh&M0nHWDKc8fhMWKjN6zA({96Xa5G`4taI4tlSXmU8v;&1B zTDT|gl0`A(9Z)#DA#1Xt9Ez1bazNFu?@z8r6{9i*x(a2fc`5lt@tG+KX+`g3PegqTHcHqtdT)HSkD&dDq; zfn;r{OLf!oi*yrpON&#BxDD>PrsSVC?gIM^Y>G5arJQxaaC}3 V40d*Oaplt7emaNI^zfny0st|qa~1#q delta 771 zcmZo@;B0unF+p08nSp^p8Hiy(ZlaDcBlE_D`TQJ$yg)&5cKylh0{WXB6@Ic!))zNn zH&8Gzu`;ljoF#6|%rwVm@&a)sxY$XMm|y7R|Kb{OF+B;OSZl=O6bS{mST{(lL3#2) z2|2jfGoToY&7#RNlA3TaA4y|okw2-En z>O-%&eyig6ZhX4nU32~02S?{=i+=4!Oasnj0WX9y*GAM><$pVExn@*0EMR7?x zP?$M!!sK1DD2BWPsor{XvZ5S{l|FJn)utaN*P{xr0tz$reV%+*P6gQ|-0~nRxhLDn z%OMM=0fm{9?oOU5k7DInc>^vM%lllQWW!%EnO#ADv!HT4bZztbvp3@T-CQa{3V4TXtePp^~BI8t!#Ju#< p#Pn3n?fViLtvR+&2w;q4oSqxSSj5b4z_>Y%k%e*l=^RGW!vJ@=*7^Vd From 282b56f0df099048918a4d94c4b19968f256ca81 Mon Sep 17 00:00:00 2001 From: boxbeam Date: Tue, 16 Apr 2024 14:05:23 -0400 Subject: [PATCH 10/15] Add test case --- ee/tabby-db/src/github_repository_provider.rs | 6 +- .../src/schema/github_repository_provider.rs | 11 +- ee/tabby-webserver/src/schema/mod.rs | 5 +- ee/tabby-webserver/src/service/dao.rs | 1 + .../src/service/github_repository_provider.rs | 102 ++++++++++++++++-- 5 files changed, 111 insertions(+), 14 deletions(-) diff --git a/ee/tabby-db/src/github_repository_provider.rs b/ee/tabby-db/src/github_repository_provider.rs index 3efa0bcd2eac..2f7b9603e91e 100644 --- a/ee/tabby-db/src/github_repository_provider.rs +++ b/ee/tabby-db/src/github_repository_provider.rs @@ -112,10 +112,10 @@ impl DbConn { vendor_id: String, name: String, git_url: String, - ) -> Result<()> { - query!("INSERT INTO github_provided_repositories (github_repository_provider_id, vendor_id, name, git_url) VALUES (?, ?, ?, ?)", + ) -> Result { + let res = query!("INSERT INTO github_provided_repositories (github_repository_provider_id, vendor_id, name, git_url) VALUES (?, ?, ?, ?)", github_provider_id, vendor_id, name, git_url).execute(&self.pool).await?; - Ok(()) + Ok(res.last_insert_rowid()) } pub async fn delete_github_provided_repository(&self, id: i64) -> Result<()> { diff --git a/ee/tabby-webserver/src/schema/github_repository_provider.rs b/ee/tabby-webserver/src/schema/github_repository_provider.rs index 68989ddeadcd..0484467562e3 100644 --- a/ee/tabby-webserver/src/schema/github_repository_provider.rs +++ b/ee/tabby-webserver/src/schema/github_repository_provider.rs @@ -11,6 +11,16 @@ pub struct GithubRepositoryProvider { pub id: ID, pub display_name: String, pub application_id: String, + pub access_token: Option, +} + +impl GithubRepositoryProvider { + pub fn strip_access_token(self) -> Self { + Self { + access_token: None, + ..self + } + } } impl NodeType for GithubRepositoryProvider { @@ -60,7 +70,6 @@ impl NodeType for GithubProvidedRepository { pub trait GithubRepositoryProviderService: Send + Sync { async fn get_github_repository_provider(&self, id: ID) -> Result; async fn read_github_repository_provider_secret(&self, id: ID) -> Result; - async fn read_github_repository_provider_access_token(&self, id: ID) -> Result; async fn update_github_repository_provider_access_token( &self, id: ID, diff --git a/ee/tabby-webserver/src/schema/mod.rs b/ee/tabby-webserver/src/schema/mod.rs index 49fbb3bcbb5b..5116e2a5b4a3 100644 --- a/ee/tabby-webserver/src/schema/mod.rs +++ b/ee/tabby-webserver/src/schema/mod.rs @@ -250,7 +250,10 @@ impl Query { .locator .github_repository_provider() .list_github_repository_providers(after, before, first, last) - .await?) + .await? + .into_iter() + .map(|provider| provider.strip_access_token()) + .collect()) }, ) .await diff --git a/ee/tabby-webserver/src/service/dao.rs b/ee/tabby-webserver/src/service/dao.rs index 08542cf39d2b..aa65cb3278c9 100644 --- a/ee/tabby-webserver/src/service/dao.rs +++ b/ee/tabby-webserver/src/service/dao.rs @@ -126,6 +126,7 @@ impl From for GithubRepositoryProvider { display_name: value.display_name, application_id: value.application_id, id: value.id.as_id(), + access_token: value.access_token, } } } diff --git a/ee/tabby-webserver/src/service/github_repository_provider.rs b/ee/tabby-webserver/src/service/github_repository_provider.rs index e99cb4ee90da..7a4bf99176a4 100644 --- a/ee/tabby-webserver/src/service/github_repository_provider.rs +++ b/ee/tabby-webserver/src/service/github_repository_provider.rs @@ -1,4 +1,3 @@ -use anyhow::anyhow; use async_trait::async_trait; use juniper::ID; use tabby_db::DbConn; @@ -34,14 +33,6 @@ impl GithubRepositoryProviderService for GithubRepositoryProviderServiceImpl { Ok(provider.secret) } - async fn read_github_repository_provider_access_token(&self, id: ID) -> Result { - let provider = self.db.get_github_provider(id.as_rowid()?).await?; - let Some(access_token) = provider.access_token else { - return Err(anyhow!("Provider has no access token").into()); - }; - Ok(access_token) - } - async fn update_github_repository_provider_access_token( &self, id: ID, @@ -102,3 +93,96 @@ impl GithubRepositoryProviderService for GithubRepositoryProviderServiceImpl { Ok(()) } } + +#[cfg(test)] +mod tests { + use crate::service::AsID; + + use super::*; + + #[tokio::test] + async fn test_github_provided_repositories() { + let db = DbConn::new_in_memory().await.unwrap(); + let service = new_github_repository_provider_service(db.clone()); + + let provider_id1 = db + .create_github_provider( + "test_provider1".into(), + "test_id1".into(), + "test_secret".into(), + ) + .await + .unwrap(); + + let provider_id2 = db + .create_github_provider( + "test_provider2".into(), + "test_id2".into(), + "test_secret".into(), + ) + .await + .unwrap(); + + let repo_id1 = db + .create_github_provided_repository( + provider_id1, + "vendor_id1".into(), + "test_repo1".into(), + "https://github.com/test/test1".into(), + ) + .await + .unwrap(); + + let repo_id2 = db + .create_github_provided_repository( + provider_id2, + "vendor_id2".into(), + "test_repo2".into(), + "https://github.com/test/test2".into(), + ) + .await + .unwrap(); + + // Test listing with no filter on providers + let repos = service + .list_github_provided_repositories_by_provider(vec![], None, None, None, None) + .await + .unwrap(); + + assert_eq!(repos.len(), 2); + assert_eq!(repos[0].name, "test_repo1"); + assert_eq!(repos[1].name, "test_repo2"); + + // Test listing with a filter on providers + let repos = service + .list_github_provided_repositories_by_provider( + vec![provider_id1.as_id()], + None, + None, + None, + None, + ) + .await + .unwrap(); + + assert_eq!(repos.len(), 1); + assert_eq!(repos[0].name, "test_repo1"); + + // Test deletion and toggling active status + db.delete_github_provided_repository(repo_id1) + .await + .unwrap(); + + db.update_github_provided_repository_active(repo_id2, true) + .await + .unwrap(); + + let repos = service + .list_github_provided_repositories_by_provider(vec![], None, None, None, None) + .await + .unwrap(); + + assert_eq!(repos.len(), 1); + assert_eq!(repos[0].active, true); + } +} From 17be87a1dd8422ff041d1f96aacb646065ac8422 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 18:13:10 +0000 Subject: [PATCH 11/15] [autofix.ci] apply automated fixes --- ee/tabby-webserver/graphql/schema.graphql | 1 + ee/tabby-webserver/src/service/github_repository_provider.rs | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ee/tabby-webserver/graphql/schema.graphql b/ee/tabby-webserver/graphql/schema.graphql index b3f81884c1f7..ba3b004cd385 100644 --- a/ee/tabby-webserver/graphql/schema.graphql +++ b/ee/tabby-webserver/graphql/schema.graphql @@ -102,6 +102,7 @@ type GithubRepositoryProvider { id: ID! displayName: String! applicationId: String! + accessToken: String } input PasswordChangeInput { diff --git a/ee/tabby-webserver/src/service/github_repository_provider.rs b/ee/tabby-webserver/src/service/github_repository_provider.rs index 7a4bf99176a4..ae94a7d1ca1f 100644 --- a/ee/tabby-webserver/src/service/github_repository_provider.rs +++ b/ee/tabby-webserver/src/service/github_repository_provider.rs @@ -96,9 +96,8 @@ impl GithubRepositoryProviderService for GithubRepositoryProviderServiceImpl { #[cfg(test)] mod tests { - use crate::service::AsID; - use super::*; + use crate::service::AsID; #[tokio::test] async fn test_github_provided_repositories() { @@ -183,6 +182,6 @@ mod tests { .unwrap(); assert_eq!(repos.len(), 1); - assert_eq!(repos[0].active, true); + assert!(repos[0].active); } } From b6fcc56002c319e0239de36b56d5ce969bcd6d01 Mon Sep 17 00:00:00 2001 From: boxbeam Date: Tue, 16 Apr 2024 14:40:42 -0400 Subject: [PATCH 12/15] Document access_token stripping --- ee/tabby-webserver/src/schema/github_repository_provider.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ee/tabby-webserver/src/schema/github_repository_provider.rs b/ee/tabby-webserver/src/schema/github_repository_provider.rs index 0484467562e3..6b158e0efcab 100644 --- a/ee/tabby-webserver/src/schema/github_repository_provider.rs +++ b/ee/tabby-webserver/src/schema/github_repository_provider.rs @@ -11,10 +11,13 @@ pub struct GithubRepositoryProvider { pub id: ID, pub display_name: String, pub application_id: String, + /// Will never be returned to the client / from GraphQL endpoints. + /// Make sure to strip using [Self::strip_access_token]. pub access_token: Option, } impl GithubRepositoryProvider { + /// Remove the access token for external representation. pub fn strip_access_token(self) -> Self { Self { access_token: None, From 24056779a4f6568edc14dff25c9d9b0efe7a3b91 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 18:47:45 +0000 Subject: [PATCH 13/15] [autofix.ci] apply automated fixes --- ee/tabby-webserver/graphql/schema.graphql | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ee/tabby-webserver/graphql/schema.graphql b/ee/tabby-webserver/graphql/schema.graphql index ba3b004cd385..d22bfad586a0 100644 --- a/ee/tabby-webserver/graphql/schema.graphql +++ b/ee/tabby-webserver/graphql/schema.graphql @@ -102,6 +102,10 @@ type GithubRepositoryProvider { id: ID! displayName: String! applicationId: String! + """ + Will never be returned to the client / from GraphQL endpoints. + Make sure to strip using [Self::strip_access_token]. + """ accessToken: String } From 271d4d8de18712a2bae3434184887301f46c481f Mon Sep 17 00:00:00 2001 From: boxbeam Date: Tue, 16 Apr 2024 14:54:31 -0400 Subject: [PATCH 14/15] Use graphql(skip) --- .../src/schema/github_repository_provider.rs | 13 +------------ ee/tabby-webserver/src/schema/mod.rs | 5 +---- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/ee/tabby-webserver/src/schema/github_repository_provider.rs b/ee/tabby-webserver/src/schema/github_repository_provider.rs index 6b158e0efcab..aee8d1a74a99 100644 --- a/ee/tabby-webserver/src/schema/github_repository_provider.rs +++ b/ee/tabby-webserver/src/schema/github_repository_provider.rs @@ -11,21 +11,10 @@ pub struct GithubRepositoryProvider { pub id: ID, pub display_name: String, pub application_id: String, - /// Will never be returned to the client / from GraphQL endpoints. - /// Make sure to strip using [Self::strip_access_token]. + #[graphql(skip)] pub access_token: Option, } -impl GithubRepositoryProvider { - /// Remove the access token for external representation. - pub fn strip_access_token(self) -> Self { - Self { - access_token: None, - ..self - } - } -} - impl NodeType for GithubRepositoryProvider { type Cursor = String; diff --git a/ee/tabby-webserver/src/schema/mod.rs b/ee/tabby-webserver/src/schema/mod.rs index 5116e2a5b4a3..49fbb3bcbb5b 100644 --- a/ee/tabby-webserver/src/schema/mod.rs +++ b/ee/tabby-webserver/src/schema/mod.rs @@ -250,10 +250,7 @@ impl Query { .locator .github_repository_provider() .list_github_repository_providers(after, before, first, last) - .await? - .into_iter() - .map(|provider| provider.strip_access_token()) - .collect()) + .await?) }, ) .await From 38e66451fa199287dfb97f42b82e435d462fcebf Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 16 Apr 2024 19:02:49 +0000 Subject: [PATCH 15/15] [autofix.ci] apply automated fixes --- ee/tabby-webserver/graphql/schema.graphql | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ee/tabby-webserver/graphql/schema.graphql b/ee/tabby-webserver/graphql/schema.graphql index d22bfad586a0..b3f81884c1f7 100644 --- a/ee/tabby-webserver/graphql/schema.graphql +++ b/ee/tabby-webserver/graphql/schema.graphql @@ -102,11 +102,6 @@ type GithubRepositoryProvider { id: ID! displayName: String! applicationId: String! - """ - Will never be returned to the client / from GraphQL endpoints. - Make sure to strip using [Self::strip_access_token]. - """ - accessToken: String } input PasswordChangeInput {