Skip to content

Commit 08eb47b

Browse files
committed
feat: implement client_credentials auth
1 parent aec741f commit 08eb47b

21 files changed

+682
-0
lines changed

.envrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
use flake .
2+
3+
export $(xargs <.env)

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
flake.lock linguist-generated=true

.github/workflows/ci.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: "CI"
2+
on:
3+
push:
4+
branches:
5+
- main
6+
pull_request:
7+
jobs:
8+
build:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v3
12+
- name: Install Nix
13+
uses: DeterminateSystems/nix-installer-action@main
14+
- uses: cachix/cachix-action@v12
15+
with:
16+
name: srid
17+
- name: Build 🔨
18+
run: nix run github:srid/nixci
19+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: update-flake-lock
2+
on:
3+
workflow_dispatch: # allows manual triggering
4+
schedule:
5+
- cron: '0 0 * * 0' # runs weekly on Sunday at 00:00
6+
7+
jobs:
8+
lockfile:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- name: Checkout repository
12+
uses: actions/checkout@v3
13+
- name: Install Nix
14+
uses: DeterminateSystems/nix-installer-action@main
15+
- name: Update flake.lock
16+
uses: DeterminateSystems/update-flake-lock@v14
17+
with:
18+
token: ${{ secrets.GH_TOKEN_FOR_UPDATES }}
19+
pr-title: "Update flake.lock" # Title of PR to be created
20+
pr-labels: | # Labels to be set on the PR
21+
automated

.gitignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# cabal
2+
dist
3+
dist-*
4+
cabal.project.local
5+
cabal.project.local~
6+
7+
# nix
8+
result
9+
result-*
10+
11+
# direnv
12+
.direnv
13+
14+
# .env
15+
.env

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 Joona Piirainen
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

flake.lock

Lines changed: 117 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
{
2+
description = "A simple CLI for interacting with spotify.";
3+
4+
inputs = {
5+
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
6+
systems.url = "github:nix-systems/default";
7+
flake-parts.url = "github:hercules-ci/flake-parts";
8+
haskell-flake.url = "github:srid/haskell-flake";
9+
treefmt-nix.url = "github:numtide/treefmt-nix";
10+
treefmt-nix.inputs.nixpkgs.follows = "nixpkgs";
11+
};
12+
13+
outputs = inputs:
14+
inputs.flake-parts.lib.mkFlake { inherit inputs; } {
15+
systems = import inputs.systems;
16+
imports = [
17+
inputs.haskell-flake.flakeModule
18+
inputs.treefmt-nix.flakeModule
19+
];
20+
perSystem = { self', config, pkgs, ... }: {
21+
haskellProjects.default = {
22+
23+
packages = { };
24+
25+
settings = { };
26+
27+
devShell = {
28+
hlsCheck.enable = false;
29+
};
30+
31+
autoWire = [ "packages" "apps" "checks" ];
32+
};
33+
34+
treefmt.config = {
35+
projectRootFile = "flake.nix";
36+
37+
programs.ormolu.enable = true;
38+
programs.nixpkgs-fmt.enable = true;
39+
programs.cabal-fmt.enable = true;
40+
programs.hlint.enable = true;
41+
42+
programs.ormolu.package = pkgs.haskellPackages.fourmolu;
43+
settings.formatter.ormolu = {
44+
options = [
45+
"--ghc-opt"
46+
"-XImportQualifiedPost"
47+
];
48+
};
49+
};
50+
51+
packages.default = self'.packages.spotify;
52+
apps.default = self'.apps.spotify;
53+
54+
devShells.default = pkgs.mkShell {
55+
name = "spotify";
56+
inputsFrom = [
57+
config.haskellProjects.default.outputs.devShell
58+
config.treefmt.build.devShell
59+
];
60+
nativeBuildInputs = with pkgs; [
61+
just
62+
zlib
63+
icu
64+
];
65+
};
66+
};
67+
};
68+
}

fourmolu.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
indentation: 2
2+
comma-style: leading
3+
record-brace-space: true
4+
indent-wheres: true
5+
diff-friendly-import-export: true
6+
respectful: true
7+
haddock-style: multi-line
8+
newlines-between-decls: 1

hie.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
cradle:
2+
cabal:

justfile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
default:
2+
@just --list
3+
4+
# Run hoogle
5+
docs:
6+
echo http://127.0.0.1:8888
7+
hoogle serve -p 8888 --local
8+
9+
# Run cabal repl
10+
repl *ARGS:
11+
cabal repl {{ARGS}}
12+
13+
# Autoformat the project tree
14+
fmt:
15+
treefmt
16+
17+
# Run ghcid -- auto-recompile and run `main` function
18+
run:
19+
ghcid -c "cabal repl exe:haskell-template" --warnings -T :main

lib/Spotify.hs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
module Spotify (main) where
2+
3+
import Effectful (Eff, runEff, (:>))
4+
import Effectful.Error.Static (runError)
5+
import Effectful.Reader.Static (runReader)
6+
7+
import Spotify.AppEnv
8+
import Spotify.Config
9+
import Spotify.Effect.FileSystem
10+
import Spotify.Effect.Spotify
11+
12+
prog :: (Config :> es, SpotifyAPI :> es) => Eff es TokenResponse
13+
prog = do
14+
c <- readConfig
15+
let auth = Just $ TokenAuthorization (userClientId c) (userClientSecret c)
16+
let tokReq =
17+
TokenRequest
18+
{ grant_type = ClientCredentials
19+
, code = Nothing
20+
, redirectUri = Nothing
21+
, refreshToken = Nothing
22+
}
23+
makeTokenRequest auth tokReq
24+
25+
main :: IO ()
26+
main = do
27+
env <- AppEnv <$> accountsEnv <*> mainEnv
28+
res <-
29+
runEff
30+
. runError @SpotifyAPIError
31+
. runError @FsError
32+
. runReader @AppEnv env
33+
. runFileSystemIO
34+
. runSpotifyServant
35+
. runConfigIO
36+
$ prog
37+
print res

lib/Spotify/AppEnv.hs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module Spotify.AppEnv (AppEnv (..)) where
2+
3+
import Servant.Client (ClientEnv)
4+
5+
data AppEnv = AppEnv
6+
{ accountsApiEnv :: ClientEnv
7+
, mainApiEnv :: ClientEnv
8+
}

lib/Spotify/Config.hs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{-# LANGUAGE TemplateHaskell #-}
2+
3+
module Spotify.Config (
4+
Config (..),
5+
UserConfig (..),
6+
readConfig,
7+
runConfigIO,
8+
) where
9+
10+
import Dhall
11+
import Effectful
12+
import Effectful.Dispatch.Dynamic
13+
import Effectful.TH
14+
15+
import Spotify.Effect.FileSystem
16+
17+
data UserConfig = UserConfig
18+
{ userClientId :: Text
19+
, userClientSecret :: Text
20+
}
21+
deriving stock (Generic, Show)
22+
23+
instance FromDhall UserConfig
24+
25+
data Config :: Effect where
26+
ReadConfig :: Config m UserConfig
27+
28+
makeEffect ''Config
29+
30+
runConfigIO :: (IOE :> es, FileSystem :> es) => Eff (Config : es) a -> Eff es a
31+
runConfigIO = interpret $ \_ -> \case
32+
ReadConfig -> readConfigFile "Spotify.dhall" >>= \c -> liftIO (input auto c)

0 commit comments

Comments
 (0)