diff --git a/spago.yaml b/spago.yaml index a8c16f6..cf5d34f 100644 --- a/spago.yaml +++ b/spago.yaml @@ -1,21 +1,70 @@ package: dependencies: - - prelude - aff + - console - effect - either - - maybe - foldable-traversable - - console + - maybe + - mmorph - newtype + - prelude - strings - stringutils - transformers - tuples - typelevel-prelude - name: project + - url + - fetch + name: gitea workspace: - extra_packages: {} + extra_packages: + fetch: + git: 'https://git.orionkindel.com/thunderstrike/purescript-fetch.git' + ref: '01f505d' + dependencies: + - aff + - aff-promise + - arraybuffer + - arraybuffer-types + - bifunctors + - effect + - either + - exceptions + - foldable-traversable + - foreign + - foreign-object + - integers + - maybe + - newtype + - node-buffer + - node-url + - nullable + - numbers + - ordered-collections + - prelude + - simple-json + - transformers + - tuples + - unsafe-coerce + - web-file + - url + url: + git: 'https://git.orionkindel.com/thunderstrike/purescript-url-immutable.git' + ref: 'dbfa3b6' + dependencies: + - arrays + - effect + - filterable + - foldable-traversable + - integers + - maybe + - newtype + - nullable + - ordered-collections + - prelude + - strings + - tuples package_set: url: https://raw.githubusercontent.com/purescript/package-sets/psc-0.15.10-20230930/packages.json hash: sha256-nTsd44o7/hrTdk0c6dh0wyBqhFFDJJIeKdQU6L1zv/A= diff --git a/src/Gitea.Auth.purs b/src/Gitea.Auth.purs new file mode 100644 index 0000000..d2190b4 --- /dev/null +++ b/src/Gitea.Auth.purs @@ -0,0 +1,51 @@ +module Gitea.Auth where + +import Prelude + +import Data.Eq.Generic (genericEq) +import Data.Generic.Rep (class Generic) +import Data.Newtype (class Newtype) +import Data.Show.Generic (genericShow) +import Effect (Effect) +import HTTP.Header as HTTP + +newtype BearerToken = BearerToken String + +derive instance Newtype BearerToken _ +derive newtype instance Show BearerToken +derive newtype instance Eq BearerToken + +newtype AccessToken = AccessToken String + +derive instance Newtype AccessToken _ +derive newtype instance Show AccessToken +derive newtype instance Eq AccessToken + +newtype Username = Username String + +derive instance Newtype Username _ +derive newtype instance Show Username +derive newtype instance Eq Username + +newtype Password = Password String + +derive instance Newtype Password _ +derive newtype instance Show Password +derive newtype instance Eq Password + +data Authenticated + = AuthBearer BearerToken + | AuthAccessToken AccessToken + | AuthBasic Username Password + +derive instance Generic Authenticated _ +instance Eq Authenticated where + eq = genericEq + +instance Show Authenticated where + show = genericShow + +authHeaders :: Authenticated -> Effect HTTP.Headers +authHeaders (AuthBearer (BearerToken token)) = HTTP.headers $ HTTP.AuthBearer token +authHeaders (AuthBasic (Username un) (Password pw)) = HTTP.headers $ HTTP.AuthBasic { username: un, password: pw } +authHeaders (AuthAccessToken (AccessToken token)) = HTTP.headers $ HTTP.AuthCustom (HTTP.AuthScheme "token") token diff --git a/src/Gitea.Config.purs b/src/Gitea.Config.purs new file mode 100644 index 0000000..ad35e9e --- /dev/null +++ b/src/Gitea.Config.purs @@ -0,0 +1,6 @@ +module Gitea.Config where + +import Data.URL (URL) +import Gitea.Auth (Authenticated) + +type Config = { baseURI :: URL, auth :: Authenticated } diff --git a/src/Gitea.Model.purs b/src/Gitea.Model.purs new file mode 100644 index 0000000..a8e89a9 --- /dev/null +++ b/src/Gitea.Model.purs @@ -0,0 +1,222 @@ +module Gitea.Model where + +import Prelude + +import Foreign.Object (Object) +import Type.Row (type (+)) + +type Permission = + { "admin" :: Boolean + , "pull" :: Boolean + , "push" :: Boolean + } + +type Organization = + { "avatar_url" :: String + , "description" :: String + , "full_name" :: String + , "id" :: Int + , "location" :: String + , "name" :: String + , "repo_admin_change_team_access" :: Boolean + , "username" :: String + , "visibility" :: String + , "website" :: String + } + +type Team = + { "can_create_org_repo" :: Boolean + , "description" :: String + , "id" :: Int + , "includes_all_repositories" :: Boolean + , "name" :: String + , "organization" :: Organization + , "permission" :: String + , "units" :: Array String + , "units_map" :: Object String + } + +type User = + { "active" :: Boolean + , "avatar_url" :: String + , "created" :: String + , "description" :: String + , "email" :: String + , "followers_count" :: Int + , "following_count" :: Int + , "full_name" :: String + , "id" :: Int + , "is_admin" :: Boolean + , "language" :: String + , "last_login" :: String + , "location" :: String + , "login" :: String + , "login_name" :: String + , "prohibit_login" :: Boolean + , "restricted" :: Boolean + , "starred_repos_count" :: Int + , "visibility" :: String + , "website" :: String + } + +type RepoInternalTracker = + { "allow_only_contributors_to_track_time" :: Boolean + , "enable_issue_dependencies" :: Boolean + , "enable_time_tracker" :: Boolean + } + +type RepoTransfer = + { "doer" :: User + , "recipient" :: User + , "teams" :: Array Team + } + +type RepoExternalTracker = + { "external_tracker_format" :: String + , "external_tracker_regexp_pattern" :: String + , "external_tracker_style" :: String + , "external_tracker_url" :: String + } + +type RepoExternalWiki = + { "external_wiki_url" :: String + } + +type RepoSectionMergeSettingsMutable r = + ( "allow_merge_commits" :: Boolean + , "allow_rebase" :: Boolean + , "allow_rebase_explicit" :: Boolean + , "allow_rebase_update" :: Boolean + , "allow_squash_merge" :: Boolean + , "default_merge_style" :: String + , "default_delete_branch_after_merge" :: Boolean + , "default_branch" :: String + , "ignore_whitespace_conflicts" :: Boolean + | r + ) + +type RepoPermsMutable r = + ( "default_allow_maintainer_edit" :: Boolean + | r + ) + +type RepoPermsImmutable r = + ( "permissions" :: Permission + | r + ) + +type RepoSectionVisibilityMutable r = + ( "archived" :: Boolean + , "private" :: Boolean + | r + ) + +type RepoSectionVisibilityImmutable r = + ( "archived_at" :: String + | r + ) + +type RepoSectionProfileMutable r = + ( "avatar_url" :: String + , "description" :: String + , "language" :: String + , "languages_url" :: String + , "link" :: String + , "original_url" :: String + , "website" :: String + | r + ) + +type RepoSectionProfileImmutable r = + ( "avatar_url" :: String + , "description" :: String + , "language" :: String + , "languages_url" :: String + , "link" :: String + , "original_url" :: String + , "website" :: String + | r + ) + +type RepoGiteaSettingsMutable r = + ( "has_actions" :: Boolean + , "has_issues" :: Boolean + , "has_packages" :: Boolean + , "has_projects" :: Boolean + , "has_pull_requests" :: Boolean + , "has_releases" :: Boolean + , "has_wiki" :: Boolean + | r + ) + +type RepoSectionGiteaStatsMutable r = + ( "template" :: Boolean + , "external_wiki" :: RepoExternalWiki + | r + ) + +type RepoSectionGiteaStatsImmutable r = + ( "open_issues_count" :: Int + , "open_pr_counter" :: Int + , "release_counter" :: Int + , "size" :: Int + , "stars_count" :: Int + , "watchers_count" :: Int + , "fork" :: Boolean + , "forks_count" :: Int + , "repo_transfer" :: RepoTransfer + | r + ) + +type RepoMeta = + { "id" :: Int + , "owner" :: String + , "name" :: String + , "full_name" :: String + } + +type RepoSectionStatsMutable r = + ( "name" :: String + , "full_name" :: String + , "mirror_interval" :: String + | r + ) + +type RepoSectionStatsImmutable r = + ( "id" :: Int + , "created_at" :: String + , "empty" :: Boolean + , "owner" :: User + , "updated_at" :: String + , "html_url" :: String + , "clone_url" :: String + , "ssh_url" :: String + , "mirror_interval" :: String + | r + ) + +type RepoSectionTrackerMutable r = + ( "external_tracker" :: RepoExternalTracker + , "internal_tracker" :: RepoInternalTracker + | r + ) + +type RepoSectionTrackerImmutable r = + ( "internal" :: Boolean + | r + ) + +type Repo = Record + ( RepoSectionTrackerMutable + + RepoSectionTrackerImmutable + + RepoSectionStatsMutable + + RepoSectionStatsImmutable + + RepoSectionGiteaStatsMutable + + RepoSectionGiteaStatsImmutable + + RepoGiteaSettingsMutable + + RepoPermsMutable + + RepoPermsImmutable + + RepoSectionVisibilityMutable + + RepoSectionVisibilityImmutable + + RepoSectionMergeSettingsMutable () + ) diff --git a/src/Gitea.Monad.purs b/src/Gitea.Monad.purs new file mode 100644 index 0000000..51821e2 --- /dev/null +++ b/src/Gitea.Monad.purs @@ -0,0 +1,51 @@ +module Gitea.Trans where + +import Prelude + +import Control.Alt (class Alt) +import Control.Alternative (class Alternative, class Plus) +import Control.Monad.Error.Class (class MonadError, class MonadThrow) +import Control.Monad.Morph (class MFunctor, class MMonad) +import Control.Monad.Reader (class MonadAsk, class MonadReader, ReaderT(..), asks, runReaderT) +import Control.Monad.Trans.Class (class MonadTrans) +import Control.MonadPlus (class MonadPlus) +import Data.Newtype (class Newtype, unwrap) +import Data.URL (URL) +import Effect.Aff.Class (class MonadAff) +import Effect.Class (class MonadEffect) +import Gitea.Auth (Authenticated) +import Gitea.Config (Config) + +newtype GiteaT :: (Type -> Type) -> Type -> Type +newtype GiteaT m a = GiteaT (ReaderT Config m a) + +derive instance Newtype (GiteaT m a) _ +derive newtype instance MMonad GiteaT +derive newtype instance MFunctor GiteaT +derive newtype instance MonadTrans GiteaT +derive newtype instance Monad m => MonadAsk Config (GiteaT m) +derive newtype instance Monad m => MonadReader Config (GiteaT m) + +derive newtype instance MonadPlus m => MonadPlus (GiteaT m) +derive newtype instance Monad m => Monad (GiteaT m) +derive newtype instance MonadEffect m => MonadEffect (GiteaT m) +derive newtype instance MonadAff m => MonadAff (GiteaT m) +derive newtype instance MonadThrow e m => MonadThrow e (GiteaT m) +derive newtype instance MonadError e m => MonadError e (GiteaT m) + +derive newtype instance Plus m => Plus (GiteaT m) +derive newtype instance Alternative m => Alternative (GiteaT m) +derive newtype instance Alt m => Alt (GiteaT m) +derive newtype instance Functor m => Functor (GiteaT m) +derive newtype instance Apply m => Apply (GiteaT m) +derive newtype instance Applicative m => Applicative (GiteaT m) +derive newtype instance Bind m => Bind (GiteaT m) + +url :: forall m. Monad m => GiteaT m URL +url = asks _.baseURI + +auth :: forall m. Monad m => GiteaT m Authenticated +auth = asks _.auth + +runGitea :: forall m a. Config -> GiteaT m a -> m a +runGitea config m = runReaderT (unwrap m) config diff --git a/src/Gitea.Repo.purs b/src/Gitea.Repo.purs new file mode 100644 index 0000000..d81391b --- /dev/null +++ b/src/Gitea.Repo.purs @@ -0,0 +1,3 @@ +module Gitea.Repo where + +import Prelude diff --git a/src/Main.purs b/src/Main.purs deleted file mode 100644 index ee561ac..0000000 --- a/src/Main.purs +++ /dev/null @@ -1,7 +0,0 @@ -module Main where - -import Prelude -import Effect (Effect) - -main :: Effect Unit -main = pure unit