Browse Source

Initial commit

pull/1/head
Adrian Salceanu 6 years ago
commit
05a55d3b10

+ 6
- 0
.gitignore View File

@@ -0,0 +1,6 @@
/_build
/deps
erl_crash.dump
*.ez
*.beam
.DS_Store

+ 4
- 0
README.md View File

@@ -0,0 +1,4 @@
Feedlex
=======

** TODO: Add description **

+ 27
- 0
config/config.exs View File

@@ -0,0 +1,27 @@
# This file is responsible for configuring your application
# and its dependencies with the aid of the Mix.Config module.
use Mix.Config

# This configuration is loaded before any dependency and is restricted
# to this project. If another project depends on this project, this
# file won't be loaded nor affect the parent project. For this reason,
# if you want to provide default values for your application for third-
# party users, it should be done in your mix.exs file.

# Sample configuration:
#
# config :logger, :console,
# level: :info,
# format: "$date $time [$level] $metadata$message\n",
# metadata: [:user_id]

# It is also possible to import configuration files, relative to this
# directory. For example, you can emulate configuration per environment
# by uncommenting the line below and defining dev.exs, test.exs and such.
# Configuration from the imported file will override the ones defined
# here (which is why it is important to import them last).
#

config :logger, :console, format: "$time $level $message\n"

import_config "#{Mix.env}.exs"

+ 7
- 0
config/dev.exs View File

@@ -0,0 +1,7 @@
use Mix.Config

# whether or not the app runs in sandbox mode
config :feedly, sandbox: true
config :feedly, client_id: "sandbox"
config :feedly, client_secret: "4205DQXBAP99S8SUHXI3" # (expires on 6/1/2015)
config :feedly, redirect_uri: "http://localhost:8080/" # don't forget the closing "/"

+ 4
- 0
config/prod.exs View File

@@ -0,0 +1,4 @@
use Mix.Config

# whether or not the app runs in sandbox mode
config: :feedlex, sandbox: false

+ 4
- 0
config/test.exs View File

@@ -0,0 +1,4 @@
use Mix.Config

# whether or not the app runs in sandbox mode
config: :feedlex, sandbox: true

+ 14
- 0
lib/feedlex.ex View File

@@ -0,0 +1,14 @@
defmodule Feedlex do
@moduledoc """
Wrapper around the Feedly API
"""

@feedly_api_host %{sandbox: "https://sandbox.feedly.com", live: "https://cloud.feedly.com"}

@doc """
Getter for accessing the feedly_api_host config
"""
def feedly_api_host do
@feedly_api_host
end
end

+ 90
- 0
lib/feedlex/auth.ex View File

@@ -0,0 +1,90 @@
defmodule Feedlex.Auth do
@moduledoc """
Exposes authentication and authorization functions into the Feedly API
https://developer.feedly.com/v3/auth/
"""

@feedly_auth_uri "/v3/auth/auth"
@feedly_auth_token_uri "/v3/auth/token"
@request_headers_json [{"Content-Type", "application/json; charset=UTF-8"}, {"X-Accept", "application/json"}]

@doc """
Returns the complete URI for beginning the authentication and authorization
process in the browser.
The client should redirect the user to the returned URI
"""
def authenticate_uri(opts \\ %{}) do
uri = Feedlex.feedly_api_host[opts[:env] || :sandbox] <> @feedly_auth_uri <> "?" <>
"response_type=#{opts[:response_type] || "code"}" <> "&" <>
"client_id=#{opts[:client_id] || Application.get_env(:feedly, :client_id)}" <> "&" <>
"redirect_uri=#{URI.encode_www_form(opts[:redirect_uri] || Application.get_env(:feedly, :redirect_uri))}" <> "&" <>
"scope=#{opts[:scope] || "https://cloud.feedly.com/subscriptions"}"
unless is_nil(opts[:state]), do: uri = uri <> "&state=#{URI.encode_www_form(opts[:state])}"

uri
end

@doc """
Exchanges the received Feedly authentication code for a refresh token and
an access token
"""
def access_token(opts \\ %{}) do
payload = ~s"""
{
"code":"#{opts[:code]}",
"client_id":"#{opts[:client_id] || Application.get_env(:feedly, :client_id)}",
"client_secret":"#{opts[:client_secret] || Application.get_env(:feedly, :client_secret)}",
"state":"#{URI.encode_www_form(opts[:state] || "")}",
"grant_type":"#{opts[:grant_type] || "authorization_code"}"
}
"""

uri = Feedlex.feedly_api_host[opts[:env] || :sandbox] <> @feedly_auth_token_uri <> "?" <>
"redirect_uri=#{URI.encode_www_form(opts[:redirect_uri] || Application.get_env(:feedly, :redirect_uri))}"

HTTPoison.start
HTTPoison.post!(uri, payload, @request_headers_json)
|> Feedlex.Response.parse
end

@doc """
Uses the refresh token to ask for a new access token
"""
def refresh_access_token(opts \\ %{}) do
payload = ~s"""
{
"refresh_token":"#{opts[:refresh_token]}",
"client_id":"#{opts[:client_id] || Application.get_env(:feedly, :client_id)}",
"client_secret":"#{opts[:client_secret] || Application.get_env(:feedly, :client_secret)}",
"grant_type":"refresh_token"
}
"""

uri = Feedlex.feedly_api_host[opts[:env] || :sandbox] <> @feedly_auth_token_uri

HTTPoison.start
HTTPoison.post!(uri, payload, @request_headers_json)
|> Feedlex.Response.parse
end

@doc """
Logoff - revokes the access and refresh tokens
"""
def revoke_token(opts \\ %{}) do
payload = ~s"""
{
"refresh_token":"#{opts[:refresh_token]}",
"client_id":"#{opts[:client_id] || Application.get_env(:feedly, :client_id)}",
"client_secret":"#{opts[:client_secret] || Application.get_env(:feedly, :client_secret)}",
"grant_type":"revoke_token"
}
"""

uri = Feedlex.feedly_api_host[opts[:env] || :sandbox] <> @feedly_auth_token_uri

HTTPoison.start
HTTPoison.post!(uri, payload, @request_headers_json)
|> Feedlex.Response.parse
end

end

+ 21
- 0
lib/feedlex/feed.ex View File

@@ -0,0 +1,21 @@
defmodule Feedlex.Feed do
@moduledoc """
Wrapper around the Feedly Feeds API
https://developer.feedly.com/v3/feeds/
"""
@feedly_feeds_uri "/v3/feeds"

@doc """
Return meta-data about a specific feed
"""
def one(opts \\ %{}) do
Feedlex.Request.get(api_endpoint: @feedly_feeds_uri <> "/" <> opts[:feed_id], access_token: opts[:access_token])
end

@doc """
Returns meta data for a list of feeds
"""
def many(opts \\ %{}) do
Feedlex.Request.post(api_endpoint: @feedly_feeds_uri <> "/.mget", access_token: opts[:access_token], payload: Poison.encode!(opts[:feeds]))
end
end

+ 28
- 0
lib/feedlex/request.ex View File

@@ -0,0 +1,28 @@
defmodule Feedlex.Request do
@moduledoc """
Utility module for handling request related functionality
"""

require Logger

@doc """
Makes a GET request to a feedly API, with header authentication
"""
def get(opts \\ %{}) do
Logger.info "GET: Requesting from #{Feedlex.feedly_api_host[opts[:env] || :sandbox] <> opts[:api_endpoint]}"

HTTPoison.start
HTTPoison.get!(Feedlex.feedly_api_host[opts[:env] || :sandbox] <> opts[:api_endpoint],
[{"Authorization", "OAuth #{opts[:access_token]}"}])
|> Feedlex.Response.parse
end

def post(opts \\ %{}) do
Logger.info "POST: Requesting from #{Feedlex.feedly_api_host[opts[:env] || :sandbox] <> opts[:api_endpoint]}"

HTTPoison.start
HTTPoison.post!(Feedlex.feedly_api_host[opts[:env] || :sandbox] <> opts[:api_endpoint],
opts[:payload], [{"Authorization", "OAuth #{opts[:access_token]}"}])
|> Feedlex.Response.parse
end
end

+ 21
- 0
lib/feedlex/response.ex View File

@@ -0,0 +1,21 @@
defmodule Feedlex.Response do
@moduledoc """
Utility functions for dealing with Feedly API responses
"""

@doc """
Parses the raw Feedly API response into a common format
"""
def parse(response) do
if Map.has_key?(response, :status_code) do
case response.status_code do
200 ->
{:ok, Poison.Parser.parse!(response.body)}
_ ->
{:ko, Poison.Parser.parse!(response.body)}
end
else
{:ko, response}
end
end
end

+ 20
- 0
lib/feedlex/stream.ex View File

@@ -0,0 +1,20 @@
defmodule Feedlex.Stream do
@moduledoc """
Wrapper around the Feedly Streams API
https://developer.feedly.com/v3/streams/
"""

@feedly_streams_uri "/v3/streams"

@doc """
Gets the content of a stream
"""
def content(opts \\ %{}) do
uri = @feedly_streams_uri <> "/" <> opts[:feed_id] <> "/contents?"

params = for {k, v} <- (opts[:filters] || %{}), into: "", do: Feedlex.Util.underscore_to_bumpy(k) <> "=#{v}&"

Feedlex.Request.get(api_endpoint: uri <> params,
access_token: opts[:access_token])
end
end

+ 15
- 0
lib/feedlex/subscription.ex View File

@@ -0,0 +1,15 @@
defmodule Feedlex.Subscription do
@moduledoc """
Wrapper around the Feedly Subscriptions API
https://developer.feedly.com/v3/subscriptions/
"""

@feedly_subscriptions_uri "/v3/subscriptions"

@doc """
Get all subscriptions
"""
def all(opts \\ %{}) do
Feedlex.Request.get(api_endpoint: @feedly_subscriptions_uri, access_token: opts[:access_token])
end
end

+ 21
- 0
lib/feedlex/util.ex View File

@@ -0,0 +1,21 @@
defmodule Feedlex.Util do
@moduledoc """
Generic utility functions for Pocketex
"""

@doc """
Converts an option name from Elixir's underscore_notation to Pocket's bumpyCase
"""
@spec underscore_to_bumpy(String.t) :: String.t

def underscore_to_bumpy(string) when is_bitstring(string) do
[head|tail] = String.split(string, "_")
rest = Enum.map_join(tail, &(String.capitalize &1) )

head <> rest
end

def underscore_to_bumpy(atom) when is_atom(atom) do
atom |> to_string |> underscore_to_bumpy
end
end

+ 39
- 0
mix.exs View File

@@ -0,0 +1,39 @@
defmodule Feedlex.Mixfile do
use Mix.Project

def project do
[app: :feedlex,
version: "0.0.1",
deps_path: "../../deps",
lockfile: "../../mix.lock",
elixir: "~> 1.0",
deps: deps]
end

# Configuration for the OTP application
#
# Type `mix help compile.app` for more information
def application do
[applications: [:logger]]
end

# Dependencies can be Hex packages:
#
# {:mydep, "~> 0.3.0"}
#
# Or git/path repositories:
#
# {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"}
#
# To depend on another app inside the umbrella:
#
# {:myapp, in_umbrella: true}
#
# Type `mix help deps` for more examples and options
defp deps do
[
{:httpoison, "~> 0.6"},
{:poison, "~> 1.3.1"},
]
end
end

+ 7
- 0
test/feedlex_test.exs View File

@@ -0,0 +1,7 @@
defmodule FeedlexTest do
use ExUnit.Case

test "the truth" do
assert 1 + 1 == 2
end
end

+ 1
- 0
test/test_helper.exs View File

@@ -0,0 +1 @@
ExUnit.start()

Loading…
Cancel
Save