Current section
Files
Jump to
Current section
Files
lib/blogit.ex
defmodule Blogit do
@moduledoc """
The Blogit Application module for the application :blogit.
The application is started using this module and can be used using the
public interface it provides.
What is Blogit? Blogit is a blog engine. It uses a repository (by default
a git repository) containing markdown files to build posts and
configuration for a blog. It can be used by, for example, Phoenix
application as a backend. An example of such Phoenix application is
[Blogit Web](https://github.com/meddle0x53/blogit_web).
An example of a running blog which uses Blogit and Blogit Web is the
blog of the Elixir Course of the Sofia University :
[blog.elixir-lang.bg](https://blog.elixir-lang.bg/posts).
Its repository, used by Blogit can be found here
https://github.com/ElixirCourse/blog.
Yes Blogit is the Elixir version of Octopress. That said, Blogit is very
extensible - the repository it uses can be something other than a Git one.
For example it could be FTP, local file system, Mnesia, Postgres, etc...
The only thing needed is to implement the Blogit.RepositoryProvider behaviour
and to configure Blogit to use it:
Example (`config/prod.exs`):
```elixir
config :blogit,
repository_url: "some_protocol://some_location.net",
repository_provider: Blogit.RepositoryProviders.MyProvider
```
For now the post files have to be in markdown, but this will be configurable
too. The metadata of a post is in YAML for the moment.
As Blogit is simple OTP Application with very simple public interface,
presented by this module, it can have custom front-end too.
It can be Phoenix+HTLM, Phoenix+React.js, Phoenix+ELM, it can be just
some Plug application, it can use gen_tcp or be some blog-in-the-terminal.
So Blogit is blog engine by a programmer for programmers.
"""
use Application
alias Blogit.Components.Posts
alias Blogit.Components.PostsByDate
alias Blogit.Components.Configuration
alias Blogit.Models.Post
alias Blogit.Logic.Search
@repository_provider Application.get_env(
:blogit, :repository_provider, Blogit.RepositoryProviders.Git
)
def start(_type, _args) do
Blogit.Supervisor.start_link(@repository_provider)
end
@doc """
Returns a list of Blogit.Models.Post structures representing posts in
the blog. The posts are sorted by their creation date, newest first.
All the markdown files in the configured posts folder will be transformed
into Blogit.Models.Post structures and their `created_at` meta field
will be read using the configured Blogit.RepositoryProvider.
Example configuration (`config/prod.exs`):
```elixir
config :blogit,
repository_url: "some_protocol://some_location.net",
repository_provider: Blogit.RepositoryProviders.MyProvider,
posts_folder: "path-to-the-posts-folder-relative-to-the-repository-root"
```
By default this folder is set to "." - the root of the repository.
Posts can be skipped using the `from` argument, passed to the function,
which is `0` by default. The size of the returned list is `5` by default,
but it can be changed with the second argument of the function - `size`.
By using these two arguments simple paging functionality can be implemented.
"""
@spec list_posts(non_neg_integer, non_neg_integer) :: [Post.t]
def list_posts(from \\ 0, size \\ 5) do
GenServer.call(Posts, {:list, from, size})
end
@doc """
Returns a list of Blogit.Models.Post structures representing pinned
posts in the blog. These posts are sorted by their last updated date.
All the markdown files in the configured posts folder will be transformed
into Blogit.Models.Post structures and their `updated_at` meta field
will be read using the configured Blogit.RepositoryProvider.
Pinned posts are posts which have specified `pinned: true` in their meta
data.
These are special posts which should be easy to find in the frontend
implementation.
"""
@spec list_pinned() :: [Post.t]
def list_pinned(), do: GenServer.call(Posts, :list_pinned)
@doc """
Returns a list of Blogit.Models.Post structures, filtered by given criteria.
The first argument of the function is a map of filters.
This map supports zero or more of the following keys:
* "author" - Used to filter posts by their `.meta.author` field.
* "category" - Used to filter posts by their `.meta.category` field.
* "tags" - Used to filter posts by their `.meta.tags` field.
The value for this key should a string of comma separated tags.
* "year" - Used to filter posts by their `.meta.year` field.
* "month" - Used to filter posts by their `.meta.month` field.
* "q" - A query to filter posts by their content or title. Supports text in
double quotes in order to search for phrases.
For more information on the filtering see
Blogit.Logic.Search.filter_by_params/2.
The other two arguments of the function can be used for paging.
Filtered posts can be skipped using the `from` argument,
which is `0` by default. The size of the returned list is `5` by default,
but it can be changed with the third argument of the function - `size`.
"""
@type filters :: %{String.t => Search.search_value}
@spec filter_posts(filters, non_neg_integer, non_neg_integer) :: [Post.t]
def filter_posts(params, from \\ 0, size \\ 5) do
GenServer.call(Posts, {:filter, params, from, size})
end
@doc """
Returns lists of posts grouped by years and then months for every year.
Can be used for implementing an easy-to-browse view component by years/months.
For more information see Blogit.Models.Post.collect_by_year_and_month/1.
"""
@spec posts_by_dates() :: Post.year_month_count_result
def posts_by_dates, do: GenServer.call(PostsByDate, :get)
@doc """
Returns a single post by its unique indentifier - its `name` field.
The name should be an atom.
Posts have unique names, usually constructed using the file path of their
source markdown file in the repository.
If there is no post with the given name, the atom `:error` is returned.
"""
@spec post_by_name(atom) :: Post.t | :error
def post_by_name(name), do: GenServer.call(Posts, {:by_name, name})
@doc """
Retrieves the blog configuration. The configuration is in the form
of a Blogit.Models.Configuration structure.
"""
@spec configuration :: Blogit.Models.Configuration.t
def configuration do
GenServer.call(Configuration, :get)
end
end