diff --git a/forge/gitea/Cargo.toml b/forge/gitea/Cargo.toml new file mode 100644 index 0000000..cde52df --- /dev/null +++ b/forge/gitea/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "gitea" +version = "0.1.0" +authors = ["realaravinth "] +description = "ForgeFlux StarChart - Federated forge spider" +documentation = "https://forgeflux.org/" +edition = "2021" +license = "AGPLv3 or later version" + + + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +async-trait = "0.1.51" +url = { version = "2.2.2", features = ["serde"] } + +[dependencies.forge-core] +path = "../forge-core" + +[dependencies.reqwest] +features = ["rustls-tls-native-roots", "gzip", "deflate", "brotli", "json"] +version = "0.11.10" + +[dependencies.serde] +features = ["derive"] +version = "1" + +[dependencies.serde_json] +version = "1" + +[dev-dependencies] +actix-rt = "2.7" diff --git a/forge/gitea/src/lib.rs b/forge/gitea/src/lib.rs new file mode 100644 index 0000000..9f7117f --- /dev/null +++ b/forge/gitea/src/lib.rs @@ -0,0 +1,199 @@ +/* + * ForgeFlux StarChart - A federated software forge spider + * Copyright © 2022 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use std::sync::Arc; + +use reqwest::Client; +use url::Url; + +use db_core::prelude::*; +use forge_core::dev::*; + +pub mod schema; + +const REPO_SEARCH_PATH: &str = "/api/v1/repos/search"; +const GITEA_NODEINFO: &str = "/api/v1/nodeinfo"; +const GITEA_IDENTIFIER: &str = "gitea"; + +#[derive(Clone)] +pub struct Gitea { + pub instance_url: Url, + pub client: Client, + hostname: String, +} + +impl Gitea { + pub fn new(instance_url: Url, client: Client) -> Self { + let hostname = db_core::get_hostname(&instance_url); + + Self { + instance_url, + client, + hostname, + } + } +} + +impl PartialEq for Gitea { + fn eq(&self, other: &Self) -> bool { + self.hostname == other.hostname && self.instance_url == other.instance_url + } +} + +#[async_trait] +impl SCForge for Gitea { + async fn is_forge(&self) -> bool { + let mut url = self.instance_url.clone(); + url.set_path(GITEA_NODEINFO); + + let res: serde_json::Value = self + .client + .get(url) + .send() + .await + .unwrap() + .json() + .await + .unwrap(); + if let serde_json::Value::String(software) = &res["software"]["name"] { + software == GITEA_IDENTIFIER + } else { + false + } + } + + fn get_hostname(&self) -> &str { + &self.hostname + } + + fn forge_type(&self) -> ForgeImplementation { + ForgeImplementation::Gitea + } + + async fn crawl(&self, limit: u64, page: u64) -> CrawlResp { + fn empty_is_none(s: &str) -> Option { + let s = s.trim(); + if s.is_empty() { + None + } else { + Some(s.to_owned()) + } + } + + let mut tags = Tags::default(); + let mut users = UserMap::default(); + let mut repos = Repositories::default(); + + let instance_url = self.instance_url.clone(); + + let mut url = instance_url.clone(); + url.set_path(REPO_SEARCH_PATH); + url.set_query(Some(&format!("page={page}&limit={limit}"))); + let mut res: schema::SearchResults = self + .client + .get(url) + .send() + .await + .unwrap() + .json() + .await + .unwrap(); + + fn to_user(u: schema::User, g: &Gitea) -> Arc> { + let mut profile_url = g.instance_url.clone(); + profile_url.set_path(&u.username); + let username = Arc::new(u.username); + Arc::new(User { + username, + html_link: profile_url.to_string(), + profile_photo: Some(u.avatar_url), + hostname: &g.hostname, + }) + } + + for repo in res.data.drain(0..) { + let user = if !users.contains_key(&repo.owner.username) { + let u = to_user(repo.owner, self); + let username = u.username.clone(); + users.insert(username.clone().clone(), u.clone()); + u + } else { + users.get(&repo.owner.username).unwrap().clone() + }; + + let mut url = instance_url.clone(); + url.set_path(&format!( + "/api/v1/repos/{}/{}/topics", + &user.username, repo.name + )); + + let mut topics: schema::Topics = self + .client + .get(url) + .send() + .await + .unwrap() + .json() + .await + .unwrap(); + + let mut rtopics = Vec::with_capacity(topics.topics.len()); + for t in topics.topics.drain(0..) { + let t = Arc::new(t); + if !tags.contains(&t) { + tags.insert(t.clone()); + } + rtopics.push(t); + } + + let frepo = Repository { + hostname: &self.hostname, + website: empty_is_none(&repo.website), + name: repo.name, + owner: user, + html_link: repo.html_url, + tags: Some(rtopics), + description: Some(repo.description), + }; + + repos.push(frepo); + } + CrawlResp { repos, tags, users } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use url::Url; + + pub const GITEA_HOST: &str = "http://localhost:8080"; + pub const NET_REPOSITORIES: u64 = 100; + pub const PER_CRAWL: u64 = 10; + + #[actix_rt::test] + async fn gitea_works() { + let ctx = Gitea::new(Url::parse(GITEA_HOST).unwrap(), Client::new()); + assert!(ctx.is_forge().await); + let steps = NET_REPOSITORIES / PER_CRAWL; + + for i in 0..steps { + let res = ctx.crawl(PER_CRAWL, i).await; + assert_eq!(res.repos.len() as u64, PER_CRAWL); + } + } +} diff --git a/forge/gitea/src/schema.rs b/forge/gitea/src/schema.rs new file mode 100644 index 0000000..7d28d97 --- /dev/null +++ b/forge/gitea/src/schema.rs @@ -0,0 +1,172 @@ +/* + * ForgeFlux StarChart - A federated software forge spider + * Copyright © 2usize22 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct SearchResults { + pub ok: bool, + pub data: Vec, +} + +#[derive(Debug, Clone, PartialEq, Hash, Eq, Serialize, Deserialize)] +pub struct User { + pub id: usize, + pub login: String, + pub full_name: String, + pub email: String, + pub avatar_url: String, + pub language: String, + pub is_admin: bool, + pub last_login: String, + pub created: String, + pub restricted: bool, + pub active: bool, + pub prohibit_login: bool, + pub location: String, + pub website: String, + pub description: String, + pub visibility: String, + pub followers_count: usize, + pub following_count: usize, + pub starred_repos_count: usize, + pub username: String, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Repository { + pub name: String, + pub full_name: String, + pub description: String, + pub empty: bool, + pub private: bool, + pub fork: bool, + pub template: bool, + pub parent: Option>, + pub mirror: bool, + pub size: usize, + pub html_url: String, + pub ssh_url: String, + pub clone_url: String, + pub original_url: String, + pub owner: User, + pub website: String, + pub stars_count: usize, + pub forks_count: usize, + pub watchers_count: usize, + pub open_issues_count: usize, + pub open_pr_counter: usize, + pub release_counter: usize, + pub default_branch: String, + pub archived: bool, + pub created_at: String, + pub updated_at: String, + pub internal_tracker: InternalIssueTracker, + pub has_issues: bool, + pub has_wiki: bool, + pub has_pull_requests: bool, + pub has_projects: bool, + pub ignore_whitespace_conflicts: bool, + pub allow_merge_commits: bool, + pub allow_rebase: bool, + pub allow_rebase_explicit: bool, + pub allow_squash_merge: bool, + pub default_merge_style: String, + pub avatar_url: String, + pub internal: bool, + pub mirror_interval: String, + pub mirror_updated: String, + pub repo_transfer: Option, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct InternalIssueTracker { + pub enable_time_tracker: bool, + pub allow_only_contributors_to_track_time: bool, + pub enable_issue_dependencies: bool, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct RepoTransfer { + pub doer: User, + pub recipient: User, + pub teams: Option, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Hash, Deserialize)] +pub struct Organization { + pub avatar_url: String, + pub description: String, + pub full_name: String, + pub id: u64, + pub location: String, + pub repo_admin_change_team_access: bool, + pub username: String, + pub visibility: String, + pub website: String, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Hash, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum Permission { + None, + Read, + Write, + Admin, + Owner, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Team { + pub can_create_org_repo: bool, + pub description: String, + pub id: u64, + pub includes_all_repositories: bool, + pub name: String, + pub organization: Organization, + pub permission: Permission, + pub units: Vec, + pub units_map: HashMap, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Topics { + pub topics: Vec, +} + +#[cfg(test)] +mod tests { + use super::*; + + use std::fs; + + #[test] + /// Tests if Gitea responses panic when deserialized with serde into structs defined in this + /// module/file. Since Go doesn't have abilities to describe nullable values, I(@realaravinth) + /// am forced to do this as I my knowledge about Gitea codebase is very limited. + fn schema_doesnt_panic() { + let files = ["./tests/schema/gitea/git.batsense.net.json"]; + for file in files.iter() { + let contents = fs::read_to_string(file).unwrap(); + for line in contents.lines() { + let _: SearchResults = serde_json::from_str(line).expect("Gitea schema paniced"); + } + } + } +} diff --git a/forge/gitea/tests/schema/gitea/git.batsense.net.json b/forge/gitea/tests/schema/gitea/git.batsense.net.json new file mode 100644 index 0000000..f42b562 --- /dev/null +++ b/forge/gitea/tests/schema/gitea/git.batsense.net.json @@ -0,0 +1,2 @@ +{"ok":true,"data":[{"id":5,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"analysis-of-captcha-systems","full_name":"realaravinth/analysis-of-captcha-systems","description":"","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":109,"html_url":"https://git.batsense.net/realaravinth/analysis-of-captcha-systems","ssh_url":"git@git.batsense.net:realaravinth/analysis-of-captcha-systems.git","clone_url":"https://git.batsense.net/realaravinth/analysis-of-captcha-systems.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-09-20T15:50:21+05:30","updated_at":"2021-09-21T18:06:09+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":32,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"fediparty-wiki","full_name":"realaravinth/fediparty-wiki","description":"","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":435,"html_url":"https://git.batsense.net/realaravinth/fediparty-wiki","ssh_url":"git@git.batsense.net:realaravinth/fediparty-wiki.git","clone_url":"https://git.batsense.net/realaravinth/fediparty-wiki.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-01-13T13:10:42+05:30","updated_at":"2022-01-13T13:11:24+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":26,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"ff-spec","full_name":"realaravinth/ff-spec","description":"notes, spec and all things forged fed","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":true,"size":142,"html_url":"https://git.batsense.net/realaravinth/ff-spec","ssh_url":"git@git.batsense.net:realaravinth/ff-spec.git","clone_url":"https://git.batsense.net/realaravinth/ff-spec.git","original_url":"https://github.com/forgefedv2/spec","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-01-01T17:50:17+05:30","updated_at":"2022-01-19T18:38:20+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"8h0m0s","mirror_updated":"2022-04-02T15:42:42+05:30","repo_transfer":null},{"id":18,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"fork-ex","full_name":"realaravinth/fork-ex","description":"","empty":true,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":80,"html_url":"https://git.batsense.net/realaravinth/fork-ex","ssh_url":"git@git.batsense.net:realaravinth/fork-ex.git","clone_url":"https://git.batsense.net/realaravinth/fork-ex.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-12-21T14:53:38+05:30","updated_at":"2021-12-21T14:53:38+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":22,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"fork-ex2","full_name":"realaravinth/fork-ex2","description":"","empty":false,"private":false,"fork":true,"template":false,"parent":{"id":19,"owner":{"id":2,"login":"bot","full_name":"","email":"bot@batsense.net","avatar_url":"https://git.batsense.net/avatar/a4edc8a838d6e28ddc38ab12aeb9d9cd","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-29T15:18:42+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"bot"},"name":"fork-ex","full_name":"bot/fork-ex","description":"","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":89,"html_url":"https://git.batsense.net/bot/fork-ex","ssh_url":"git@git.batsense.net:bot/fork-ex.git","clone_url":"https://git.batsense.net/bot/fork-ex.git","original_url":"","website":"","stars_count":0,"forks_count":1,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-12-21T14:56:50+05:30","updated_at":"2021-12-21T14:56:53+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},"mirror":false,"size":89,"html_url":"https://git.batsense.net/realaravinth/fork-ex2","ssh_url":"git@git.batsense.net:realaravinth/fork-ex2.git","clone_url":"https://git.batsense.net/realaravinth/fork-ex2.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-12-22T16:58:46+05:30","updated_at":"2021-12-22T16:58:46+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":6,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"git-sandbox","full_name":"realaravinth/git-sandbox","description":"","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":103,"html_url":"https://git.batsense.net/realaravinth/git-sandbox","ssh_url":"git@git.batsense.net:realaravinth/git-sandbox.git","clone_url":"https://git.batsense.net/realaravinth/git-sandbox.git","original_url":"","website":"","stars_count":0,"forks_count":1,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-09-29T13:09:42+05:30","updated_at":"2021-09-29T18:14:27+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":42,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"hostea-organization","full_name":"realaravinth/hostea-organization","description":"Organization of the hostea project","empty":false,"private":false,"fork":true,"template":false,"parent":{"id":41,"owner":{"id":5,"login":"Hostea","full_name":"","email":"","avatar_url":"https://git.batsense.net/avatars/fbade9e36a3f36d3d676c1b808451dd7","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2022-03-14T23:24:35+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://pad.batsense.net/wiEY8U7pSpCuZLz7gZVJoQ?view#","description":"Managed Gitea Hosting\r\n\r\npreviously: Project Z and Gitea managed hosting","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"Hostea"},"name":"organization","full_name":"Hostea/organization","description":"Organization of the hostea project","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":278,"html_url":"https://git.batsense.net/Hostea/organization","ssh_url":"git@git.batsense.net:Hostea/organization.git","clone_url":"https://git.batsense.net/Hostea/organization.git","original_url":"","website":"","stars_count":0,"forks_count":1,"watchers_count":2,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-03-22T16:55:57+05:30","updated_at":"2022-04-01T22:37:53+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},"mirror":false,"size":194,"html_url":"https://git.batsense.net/realaravinth/hostea-organization","ssh_url":"git@git.batsense.net:realaravinth/hostea-organization.git","clone_url":"https://git.batsense.net/realaravinth/hostea-organization.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-04-01T15:04:14+05:30","updated_at":"2022-04-01T15:04:14+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":35,"owner":{"id":5,"login":"Hostea","full_name":"","email":"","avatar_url":"https://git.batsense.net/avatars/fbade9e36a3f36d3d676c1b808451dd7","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2022-03-14T23:24:35+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://pad.batsense.net/wiEY8U7pSpCuZLz7gZVJoQ?view#","description":"Managed Gitea Hosting\r\n\r\npreviously: Project Z and Gitea managed hosting","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"Hostea"},"name":"july-mvp","full_name":"Hostea/july-mvp","description":"100% Free Software Managed Gitea Hosting MVP scheduled for July 2022","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":148,"html_url":"https://git.batsense.net/Hostea/july-mvp","ssh_url":"git@git.batsense.net:Hostea/july-mvp.git","clone_url":"https://git.batsense.net/Hostea/july-mvp.git","original_url":"","website":"","stars_count":2,"forks_count":1,"watchers_count":2,"open_issues_count":28,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-03-14T23:31:53+05:30","updated_at":"2022-03-23T10:55:49+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":41,"owner":{"id":5,"login":"Hostea","full_name":"","email":"","avatar_url":"https://git.batsense.net/avatars/fbade9e36a3f36d3d676c1b808451dd7","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2022-03-14T23:24:35+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://pad.batsense.net/wiEY8U7pSpCuZLz7gZVJoQ?view#","description":"Managed Gitea Hosting\r\n\r\npreviously: Project Z and Gitea managed hosting","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"Hostea"},"name":"organization","full_name":"Hostea/organization","description":"Organization of the hostea project","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":278,"html_url":"https://git.batsense.net/Hostea/organization","ssh_url":"git@git.batsense.net:Hostea/organization.git","clone_url":"https://git.batsense.net/Hostea/organization.git","original_url":"","website":"","stars_count":0,"forks_count":1,"watchers_count":2,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-03-22T16:55:57+05:30","updated_at":"2022-04-01T22:37:53+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":37,"owner":{"id":5,"login":"Hostea","full_name":"","email":"","avatar_url":"https://git.batsense.net/avatars/fbade9e36a3f36d3d676c1b808451dd7","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2022-03-14T23:24:35+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://pad.batsense.net/wiEY8U7pSpCuZLz7gZVJoQ?view#","description":"Managed Gitea Hosting\r\n\r\npreviously: Project Z and Gitea managed hosting","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"Hostea"},"name":"payments","full_name":"Hostea/payments","description":"","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":148,"html_url":"https://git.batsense.net/Hostea/payments","ssh_url":"git@git.batsense.net:Hostea/payments.git","clone_url":"https://git.batsense.net/Hostea/payments.git","original_url":"","website":"","stars_count":1,"forks_count":0,"watchers_count":2,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-03-16T15:12:05+05:30","updated_at":"2022-03-19T20:54:23+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":34,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"rust-async","full_name":"realaravinth/rust-async","description":"","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":88,"html_url":"https://git.batsense.net/realaravinth/rust-async","ssh_url":"git@git.batsense.net:realaravinth/rust-async.git","clone_url":"https://git.batsense.net/realaravinth/rust-async.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-02-24T22:06:00+05:30","updated_at":"2022-02-24T23:04:57+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":15,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"testing","full_name":"realaravinth/testing","description":"test-description","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":93,"html_url":"https://git.batsense.net/realaravinth/testing","ssh_url":"git@git.batsense.net:realaravinth/testing.git","clone_url":"https://git.batsense.net/realaravinth/testing.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":1,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-12-21T11:37:55+05:30","updated_at":"2022-03-19T18:41:16+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":10,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"tmp","full_name":"realaravinth/tmp","description":"test repo","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":417,"html_url":"https://git.batsense.net/realaravinth/tmp","ssh_url":"git@git.batsense.net:realaravinth/tmp.git","clone_url":"https://git.batsense.net/realaravinth/tmp.git","original_url":"","website":"","stars_count":0,"forks_count":1,"watchers_count":2,"open_issues_count":3,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-10-23T10:08:50+05:30","updated_at":"2021-11-28T14:30:49+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":13,"owner":{"id":1,"login":"realaravinth","full_name":"Aravinth Manivannan","email":"realaravinth@batsense.net","avatar_url":"https://git.batsense.net/avatars/bc11e95d9356ac4bdc035964be00ff0d","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-10T18:44:04+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"Internet","website":"https://batsense.net","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":2,"username":"realaravinth"},"name":"tmp22","full_name":"realaravinth/tmp22","description":"lib created","empty":false,"private":false,"fork":true,"template":false,"parent":{"id":11,"owner":{"id":2,"login":"bot","full_name":"","email":"bot@batsense.net","avatar_url":"https://git.batsense.net/avatar/a4edc8a838d6e28ddc38ab12aeb9d9cd","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2021-09-29T15:18:42+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"bot"},"name":"tmp2","full_name":"bot/tmp2","description":"https://git.batsense.net/bot/tmp2","empty":false,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":418,"html_url":"https://git.batsense.net/bot/tmp2","ssh_url":"git@git.batsense.net:bot/tmp2.git","clone_url":"https://git.batsense.net/bot/tmp2.git","original_url":"","website":"","stars_count":0,"forks_count":1,"watchers_count":1,"open_issues_count":3,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-10-23T16:56:59+05:30","updated_at":"2022-01-01T13:28:38+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},"mirror":false,"size":430,"html_url":"https://git.batsense.net/realaravinth/tmp22","ssh_url":"git@git.batsense.net:realaravinth/tmp22.git","clone_url":"https://git.batsense.net/realaravinth/tmp22.git","original_url":"","website":"","stars_count":0,"forks_count":0,"watchers_count":1,"open_issues_count":0,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2021-10-23T18:32:21+05:30","updated_at":"2021-10-23T18:32:21+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":true,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null},{"id":38,"owner":{"id":5,"login":"Hostea","full_name":"","email":"","avatar_url":"https://git.batsense.net/avatars/fbade9e36a3f36d3d676c1b808451dd7","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2022-03-14T23:24:35+05:30","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"https://pad.batsense.net/wiEY8U7pSpCuZLz7gZVJoQ?view#","description":"Managed Gitea Hosting\r\n\r\npreviously: Project Z and Gitea managed hosting","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"Hostea"},"name":"user-research","full_name":"Hostea/user-research","description":"User Research https://jdittrich.github.io/userNeedResearchBook/","empty":true,"private":false,"fork":false,"template":false,"parent":null,"mirror":false,"size":80,"html_url":"https://git.batsense.net/Hostea/user-research","ssh_url":"git@git.batsense.net:Hostea/user-research.git","clone_url":"https://git.batsense.net/Hostea/user-research.git","original_url":"","website":"","stars_count":2,"forks_count":0,"watchers_count":2,"open_issues_count":6,"open_pr_counter":0,"release_counter":0,"default_branch":"master","archived":false,"created_at":"2022-03-19T12:46:53+05:30","updated_at":"2022-03-19T12:46:54+05:30","permissions":{"admin":false,"push":false,"pull":true},"has_issues":true,"internal_tracker":{"enable_time_tracker":false,"allow_only_contributors_to_track_time":true,"enable_issue_dependencies":true},"has_wiki":true,"has_pull_requests":true,"has_projects":true,"ignore_whitespace_conflicts":false,"allow_merge_commits":true,"allow_rebase":true,"allow_rebase_explicit":true,"allow_squash_merge":true,"default_merge_style":"merge","avatar_url":"","internal":false,"mirror_interval":"","mirror_updated":"0001-01-01T00:00:00Z","repo_transfer":null}]} +{"ok":true,"data":[]}