Add datetime support and update to Elixir 1.4, bump all deps, fix warns

This commit is contained in:
Mikko Ahlroth 2017-01-21 14:05:45 +02:00
parent b33c48c8db
commit b80cb5433f
13 changed files with 163 additions and 94 deletions

View file

@ -5,6 +5,8 @@ defmodule MebeEngine.Crawler do
"""
require Logger
alias Calendar.DateTime
alias MebeEngine.Parser
alias MebeEngine.Models.Page
@ -47,16 +49,14 @@ defmodule MebeEngine.Crawler do
Page -> %{acc | pages: Map.put(acc.pages, pagedata.slug, pagedata)}
Post ->
{year, month, _} = pagedata.date
{{year, month, _}, _} = DateTime.to_erl(pagedata.datetime)
tags = Enum.reduce(pagedata.tags, acc.tags, fn tag, tagmap ->
posts = Map.get(tagmap, tag, [])
Map.put(tagmap, tag, [pagedata | posts])
end)
authors = %{}
author_names = %{}
if multi_author_mode do
{authors, author_names} = if multi_author_mode do
author_name = Utils.get_author(pagedata)
author_slug = Utils.slugify(author_name)
author_posts = [pagedata | Map.get(acc.authors, author_slug, [])]
@ -64,6 +64,10 @@ defmodule MebeEngine.Crawler do
# Authors end up with the name that was in the post with the first matching slug
author_names = Map.put_new(acc.author_names, author_slug, author_name)
{authors, author_names}
else
{%{}, %{}}
end
year_posts = [pagedata | Map.get(acc.years, year, [])]
@ -81,4 +85,4 @@ defmodule MebeEngine.Crawler do
end
end
end
end
end

View file

@ -2,6 +2,8 @@ defmodule MebeEngine.DB do
require Logger
alias MebeWeb.Utils
alias Calendar.DateTime
@moduledoc """
Stuff related to storing the blog data to memory (ETS).
"""
@ -68,12 +70,12 @@ defmodule MebeEngine.DB do
def insert_posts(posts) do
ordered_posts = Enum.map posts, fn post ->
{year, month, day} = post.date
{{year, month, day}, _} = DateTime.to_erl(post.datetime)
{{year, month, day, post.order}, post}
end
single_posts = Enum.map posts, fn post ->
{year, month, day} = post.date
{{year, month, day}, _} = DateTime.to_erl(post.datetime)
{{year, month, day, post.slug}, post}
end
@ -83,7 +85,7 @@ defmodule MebeEngine.DB do
if Utils.get_conf(:multi_author_mode) do
author_posts = Enum.filter(posts, fn post -> Map.has_key?(post.extra_headers, "author") end)
|> Enum.map(fn post ->
{year, month, day} = post.date
{{year, month, day}, _} = DateTime.to_erl(post.datetime)
author_slug = Utils.get_author(post) |> Utils.slugify
{{author_slug, year, month, day, post.order}, post}
@ -100,7 +102,7 @@ defmodule MebeEngine.DB do
def insert_tag_posts(tags) do
tag_posts = Enum.reduce(Map.keys(tags), [], fn tag, acc ->
Enum.reduce(tags[tag], acc, fn post, inner_acc ->
{year, month, day} = post.date
{{year, month, day}, _} = DateTime.to_erl(post.datetime)
[{{tag, year, month, day, post.order}, post} | inner_acc]
end)
end)
@ -111,7 +113,7 @@ defmodule MebeEngine.DB do
def insert_author_posts(authors) do
author_posts = Enum.reduce(Map.keys(authors), [], fn author_slug, acc ->
Enum.reduce(authors[author_slug], acc, fn post, inner_acc ->
{year, month, day} = post.date
{{year, month, day}, _} = DateTime.to_erl(post.datetime)
[{{author_slug, year, month, day, post.order}, post} | inner_acc]
end)
end)

View file

@ -13,7 +13,8 @@ defmodule MebeEngine.Models do
defmodule Post do
defstruct slug: nil,
title: nil,
date: nil,
datetime: nil,
time_given: false,
tags: [],
content: nil,
short_content: nil,

View file

@ -6,6 +6,9 @@ defmodule MebeEngine.Parser do
alias MebeEngine.Models.PageData
alias MebeEngine.Models.Page
alias MebeEngine.Models.Post
alias MebeWeb.Utils
@time_re ~R/(?<hours>\d\d):(?<minutes>\d\d)(?: (?<timezone>.*))?/
def parse(pagedata, filename) do
split_lines(pagedata)
@ -64,22 +67,57 @@ defmodule MebeEngine.Parser do
}
[_, year, month, day, order, slug] ->
[tags | extra_headers] = headers
{tags, extra_headers} = if not Enum.empty?(headers) do
[tags | extra_headers] = headers
{tags, extra_headers}
else
{"", []}
end
order = format_order order
order = format_order(order)
split_content = String.split content, ~R/<!--\s*SPLIT\s*-->/u
extra_headers = parse_headers(extra_headers)
date_erl = date_to_int_tuple({year, month, day})
date = Date.from_erl!(date_erl)
time_parts = with str when is_binary(str) <- Map.get(extra_headers, "time", nil),
%{
"hours" => hours,
"minutes" => minutes,
"timezone" => tz_str
} <- Regex.named_captures(@time_re, str) do
tz_str = if tz_str == "" do
Utils.get_conf(:time_default_tz)
else
tz_str
end
{{str_to_int(hours), str_to_int(minutes), 0}, tz_str}
end
{time, tz} = if time_parts != nil do
{time_erl, tz} = time_parts
{Time.from_erl!(time_erl), tz}
else
# If not given, time is midnight (RSS feeds require a time)
{Time.from_erl!({0, 0, 0}), Utils.get_conf(:time_default_tz)}
end
datetime = Calendar.DateTime.from_date_and_time_and_zone!(date, time, tz)
%Post{
slug: slug,
title: title,
date: date_to_int_tuple({year, month, day}),
datetime: datetime,
time_given: time_parts != nil,
tags: parse_tags(tags),
content: content,
short_content: hd(split_content),
order: order,
has_more: (Enum.count(split_content) > 1),
extra_headers: parse_headers(extra_headers)
extra_headers: extra_headers
}
end
end
@ -100,7 +138,10 @@ defmodule MebeEngine.Parser do
end
defp parse_tags(tagline) do
String.split tagline, ~R/,\s*/iu
case String.split(tagline, ~R/,\s*/iu) do
[""] -> []
list -> list
end
end
defp date_to_int_tuple({year, month, day}) do
@ -111,13 +152,16 @@ defmodule MebeEngine.Parser do
}
end
defp str_to_int("00"), do: 0
defp str_to_int(str) do
{int, _} = String.lstrip(str, ?0)
|> Integer.parse
{int, _} =
String.lstrip(str, ?0)
|> Integer.parse()
int
end
defp format_order(""), do: 0
defp format_order(order), do: str_to_int order
end
end

View file

@ -15,20 +15,20 @@ defmodule MebeEngine.Worker do
end
def init(:ok) do
load_db
load_db()
{:ok, nil}
end
def handle_call(:refresh, _from, nil) do
refresh_db
refresh_db()
{:reply, :ok, nil}
end
def refresh_db() do
Logger.info "Destroying database…"
DB.destroy
DB.destroy()
Logger.info "Reloading database…"
load_db
load_db()
Logger.info "Update done!"
end
@ -79,4 +79,4 @@ defmodule MebeEngine.Worker do
Logger.info("Posts loaded.")
end
end
end

View file

@ -13,12 +13,12 @@ defmodule MebeWeb.RequestStartTimePlug do
def call(conn, _opts) do
conn
|> assign(@data_key, get_current_time)
|> assign(@data_key, get_current_time())
end
def calculate_time(conn) do
old_time = conn.assigns[@data_key]
((get_current_time() - old_time) * 1_000_000)
|> Float.round()
|> trunc()
@ -26,7 +26,7 @@ defmodule MebeWeb.RequestStartTimePlug do
end
defp get_current_time() do
{millions, seconds, microseconds} = :os.timestamp
{millions, seconds, microseconds} = :os.timestamp()
(millions * 1_000_000) + seconds + (microseconds / 1_000_000)
end

23
mix.exs
View file

@ -3,13 +3,13 @@ defmodule MebeWeb.Mixfile do
def project do
[app: :mebe_web,
version: "1.0.0",
elixir: ">= 1.2.0 and < 1.3.0",
version: "1.1.0",
elixir: "~> 1.4.0",
elixirc_paths: elixirc_paths(Mix.env),
compilers: [:phoenix] ++ Mix.compilers,
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
deps: deps]
deps: deps()]
end
# Configuration for the OTP application
@ -17,7 +17,7 @@ defmodule MebeWeb.Mixfile do
# Type `mix help compile.app` for more information
def application do
[mod: {MebeWeb, []},
applications: [:phoenix, :cowboy, :logger, :phoenix_html, :earmark, :conform]]
applications: [:phoenix, :cowboy, :logger, :phoenix_html, :earmark, :calendar, :tzdata]]
end
# Specifies which paths to compile per environment
@ -29,14 +29,13 @@ defmodule MebeWeb.Mixfile do
# Type `mix help deps` for examples and options
defp deps do
[
{:phoenix, "~> 1.0"},
{:phoenix_live_reload, "~> 1.0", only: :dev},
{:phoenix_html, "~> 2.2"},
{:cowboy, "~> 1.0"},
{:earmark, "~> 0.2.0"},
{:exrm, "~> 1.0.0-rc5"},
{:conform, "~> 1.0.0-rc4"},
{:slugger, github: "h4cc/slugger", ref: "558e435c232034551123f034f6dd7f1f395e6759"}
{:phoenix, "~> 1.2.1"},
{:phoenix_live_reload, "~> 1.0.7", only: :dev},
{:phoenix_html, "~> 2.9.2"},
{:cowboy, "~> 1.0.4"},
{:earmark, "~> 1.0.3"},
{:slugger, github: "h4cc/slugger", ref: "ef864669cdaae18d475600589c19c74e92ef67b4"},
{:calendar, "~> 0.17.1"}
]
end
end

View file

@ -1,20 +1,31 @@
%{"bbmustache": {:hex, :bbmustache, "1.0.4"},
"calendar": {:hex, :calendar, "0.17.1", "5c7dfffde2b68011c2d6832ff1a15496292de965a3b57b3fad32405f1176f024", [:mix], [{:tzdata, "~> 0.5.8 or ~> 0.1.201603", [hex: :tzdata, optional: false]}]},
"certifi": {:hex, :certifi, "0.7.0", "861a57f3808f7eb0c2d1802afeaae0fa5de813b0df0979153cbafcd853ababaf", [:rebar3], []},
"cf": {:hex, :cf, "0.2.1"},
"conform": {:hex, :conform, "1.0.0-rc8"},
"cowboy": {:hex, :cowboy, "1.0.4"},
"cowlib": {:hex, :cowlib, "1.0.2"},
"earmark": {:hex, :earmark, "0.2.1"},
"cowboy": {:hex, :cowboy, "1.0.4", "a324a8df9f2316c833a470d918aaf73ae894278b8aa6226ce7a9bf699388f878", [:make, :rebar], [{:cowlib, "~> 1.0.0", [hex: :cowlib, optional: false]}, {:ranch, "~> 1.0", [hex: :ranch, optional: false]}]},
"cowlib": {:hex, :cowlib, "1.0.2", "9d769a1d062c9c3ac753096f868ca121e2730b9a377de23dec0f7e08b1df84ee", [:make], []},
"earmark": {:hex, :earmark, "1.0.3", "89bdbaf2aca8bbb5c97d8b3b55c5dd0cff517ecc78d417e87f1d0982e514557b", [:mix], []},
"erlware_commons": {:hex, :erlware_commons, "0.18.0"},
"exrm": {:hex, :exrm, "1.0.0-rc8"},
"fs": {:hex, :fs, "0.9.2"},
"fs": {:hex, :fs, "2.12.0", "ad631efacc9a5683c8eaa1b274e24fa64a1b8eb30747e9595b93bec7e492e25e", [:rebar3], []},
"getopt": {:hex, :getopt, "0.8.2"},
"hackney": {:hex, :hackney, "1.6.5", "8c025ee397ac94a184b0743c73b33b96465e85f90a02e210e86df6cbafaa5065", [:rebar3], [{:certifi, "0.7.0", [hex: :certifi, optional: false]}, {:idna, "1.2.0", [hex: :idna, optional: false]}, {:metrics, "1.0.1", [hex: :metrics, optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, optional: false]}]},
"idna": {:hex, :idna, "1.2.0", "ac62ee99da068f43c50dc69acf700e03a62a348360126260e87f2b54eced86b2", [:rebar3], []},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], []},
"mime": {:hex, :mime, "1.0.1", "05c393850524767d13a53627df71beeebb016205eb43bfbd92d14d24ec7a1b51", [:mix], []},
"mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], []},
"neotoma": {:hex, :neotoma, "1.7.3"},
"phoenix": {:hex, :phoenix, "1.1.4"},
"phoenix_html": {:hex, :phoenix_html, "2.5.0"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.0.3"},
"plug": {:hex, :plug, "1.1.1"},
"poison": {:hex, :poison, "2.1.0"},
"phoenix": {:hex, :phoenix, "1.2.1", "6dc592249ab73c67575769765b66ad164ad25d83defa3492dc6ae269bd2a68ab", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, optional: false]}, {:plug, "~> 1.1", [hex: :plug, optional: false]}, {:poison, "~> 1.5 or ~> 2.0", [hex: :poison, optional: false]}]},
"phoenix_html": {:hex, :phoenix_html, "2.9.2", "371160b30cf4e10443b015efce6f03e1f19aae98ff6487620477b13a5b2ef660", [:mix], [{:plug, "~> 1.0", [hex: :plug, optional: false]}]},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.0.7", "167ab0942e88d1d4a597996cf7dd8d2b014cc14d3f9472b58858cde8dd9ac2e4", [:mix], [{:fs, "~> 2.12.0", [hex: :fs, optional: false]}, {:phoenix, "~> 1.0 or ~> 1.2-rc", [hex: :phoenix, optional: false]}]},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "1.0.1", "c10ddf6237007c804bf2b8f3c4d5b99009b42eca3a0dfac04ea2d8001186056a", [:mix], []},
"plug": {:hex, :plug, "1.3.0", "6e2b01afc5db3fd011ca4a16efd9cb424528c157c30a44a0186bcc92c7b2e8f3", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1", [hex: :cowboy, optional: true]}, {:mime, "~> 1.0", [hex: :mime, optional: false]}]},
"poison": {:hex, :poison, "2.2.0", "4763b69a8a77bd77d26f477d196428b741261a761257ff1cf92753a0d4d24a63", [:mix], []},
"providers": {:hex, :providers, "1.6.0"},
"ranch": {:hex, :ranch, "1.2.1"},
"relx": {:hex, :relx, "3.16.0"},
"slugger": {:git, "https://github.com/h4cc/slugger.git", "558e435c232034551123f034f6dd7f1f395e6759", [ref: "558e435c232034551123f034f6dd7f1f395e6759"]}}
"ranch": {:hex, :ranch, "1.2.1", "a6fb992c10f2187b46ffd17ce398ddf8a54f691b81768f9ef5f461ea7e28c762", [:make], []},
"relx": {:hex, :relx, "3.17.0"},
"slugger": {:git, "https://github.com/h4cc/slugger.git", "ef864669cdaae18d475600589c19c74e92ef67b4", [ref: "ef864669cdaae18d475600589c19c74e92ef67b4"]},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], []},
"ssl_verify_hostname": {:hex, :ssl_verify_hostname, "1.0.5"},
"tzdata": {:hex, :tzdata, "0.5.10", "087e8dfe8c0283473115ad8ca6974b898ecb55ca5c725427a142a79593391e90", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, optional: false]}]}}

View file

@ -6,6 +6,6 @@
</p>
<p>
<a href="<%= home_url %>">Go away</a>.
<a href="<%= home_url() %>">Go away</a>.
</p>
</div>
</div>

View file

@ -1,22 +1,16 @@
<%= for post <- @posts do %>
<% {year, month, day} = post.date %>
<% {{year, month, day}, _} = DateTime.to_erl(post.datetime) %>
<%
# Justified versions of the month and day
{j_month, j_day} = {
String.rjust(Integer.to_string(month), 2, ?0),
String.rjust(Integer.to_string(day), 2, ?0)
}
# Justified versions of the month and day
{j_month, j_day} = {
String.rjust(Integer.to_string(month), 2, ?0),
String.rjust(Integer.to_string(day), 2, ?0)
}
%>
<%
# Quick and dirty RFC 822 month converter
rfc_month = Enum.at(["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], month - 1)
data = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]
dow_year = if month < 3, do: year - 1, else: year
dow = rem(dow_year + div(dow_year, 4) - div(dow_year, 100) + div(dow_year, 400) + Enum.at(data, month - 1) + day, 7)
dow_str = Enum.at(["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], dow - 1)
{:ok, rfc_time} = strftime(post.datetime, "%a, %e %b %Y %T %Z")
%>
<item>
@ -33,7 +27,7 @@
<description>
<![CDATA[
<%= if show_full do %>
<%= if show_full() do %>
<%= post.content %>
<% else %>
<%= post.short_content %>
@ -45,6 +39,6 @@
]]>
</description>
<pubDate><%= dow_str %>, <%= day %> <%= rfc_month %> <%= year %> 00:00:00 UT</pubDate>
<pubDate><%= rfc_time %></pubDate>
</item>
<% end %>

View file

@ -7,7 +7,7 @@
<meta name="author" content="<%= @blog_author %>">
<title><%= title @conn %></title>
<%= if @use_default_style do %>
<link rel="stylesheet" href="<%= static_path(@conn, "/css/app.css") %>">
<% end %>
@ -15,7 +15,7 @@
<%= if @custom_style_path != nil do %>
<link rel="stylesheet" href="<%= @custom_style_path %>">
<% end %>
<%= if @enable_feeds do %>
<%= if assigns[:page_type] == :tag do %>
<link href="<%= @absolute_url %><%= feed_path @conn, :tag, @tag %>" rel="alternate" type="application/rss+xml" title="RSS feed for tag <%= @tag %>" />
@ -48,7 +48,7 @@
<div class="container">
<%= render @view_module, @view_template, assigns %>
<% footer = custom_footer_html %>
<% footer = custom_footer_html() %>
<%= if footer != nil do %>
<%= raw footer %>
<%= else %>
@ -67,8 +67,8 @@
</div>
<div class="col-xs-12 col-sm-4">
<p>
<% {time, unit} = request_time @conn %>
Rendered in <%= time |> safe_round |> trunc %>&nbsp;<%= unit %>.
<% {time, unit} = request_time(@conn) %>
Rendered in <%= time |> safe_round() |> trunc() %>&nbsp;<%= unit %>.
</p>
</div>
</div>
@ -78,6 +78,6 @@
<script src="<%= static_path(@conn, "/js/app.js") %>"></script>
<script src="<%= static_path(@conn, "/js/old_hash_redirector.js") %>"></script>
<%= raw extra_html %>
<%= raw extra_html() %>
</body>
</html>

View file

@ -1,11 +1,11 @@
<% {year, month, day} = @post.date %>
<% {{year, month, day}, _} = DateTime.to_erl(@post.datetime) %>
<%
# Justified versions of the month and day
{j_month, j_day} = {
String.rjust(Integer.to_string(month), 2, ?0),
String.rjust(Integer.to_string(day), 2, ?0)
}
# Justified versions of the month and day
{j_month, j_day} = {
String.rjust(Integer.to_string(month), 2, ?0),
String.rjust(Integer.to_string(day), 2, ?0)
}
%>
<%
@ -14,7 +14,7 @@
<div class="post">
<div class="post-header">
<%= if @short do %>
<a href="<%= page_path @conn, :post, year, j_month, j_day, @post.slug %>">
<h1><%= @post.title %></h1>
@ -26,13 +26,21 @@
<div class="post-meta">
<span>
Posted on
<a href="<%= page_path @conn, :year, year, 1 %>"><%= year %>-<%= j_month %>-<%= j_day %></a><!--
--><%= if @multi_author_mode and author != nil do %><!--
--> by <a href="<%= page_path(@conn, :author, slugify(get_author(@post)), 1) %>"><%= get_author(@post) %></a><!--
--><% end %>.
<%= if @post.time_given do %>
<%= strftime!(@post.datetime, "%e %b %Y %H:%M %Z") %>
<% else %>
<%= strftime!(@post.datetime, "%e %b %Y") %>
<% end %>
<%= if @multi_author_mode and author != nil do %>
by <a href="<%= page_path(@conn, :author, slugify(get_author(@post)), 1) %>"><%= get_author(@post) %></a>
<% end %>
</span>
<%= if @post.tags do %>
<%= if not Enum.empty?(@post.tags) do %>
with tags
<ul class="post-tags">
<%= for tag <- @post.tags do %>
<li>
@ -58,7 +66,7 @@
</p>
<% end %>
</div>
<%= else %>
<% else %>
<div class="post-content">
<%= raw @post.content %>
</div>
@ -70,7 +78,7 @@
/* * * CONFIGURATION VARIABLES * * */
var disqus_shortname = "<%= @disqus_shortname %>";
var disqus_title = "<%= @post.title %>";
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
@ -83,4 +91,4 @@
</noscript>
<% end %>
</div>
</div>

View file

@ -29,16 +29,18 @@ defmodule MebeWeb.Web do
def view do
quote do
root = "web/templates"
default_root = "web/templates"
# Check if we should be using a custom template
# TODO: Enable custom views even for releases, currently always set to off
# because they use compile time configuration
custom_templates = Utils.get_conf :custom_templates
compiled_view = MebeWeb.Web.module_to_str __MODULE__
custom_templates = Utils.get_conf(:custom_templates)
compiled_view = MebeWeb.Web.module_to_str(__MODULE__)
if Map.get custom_templates, compiled_view do
root = root <> "/custom"
root = if Map.get(custom_templates, compiled_view) do
default_root <> "/custom"
else
default_root
end
use Phoenix.View, root: root
@ -51,6 +53,10 @@ defmodule MebeWeb.Web do
# Custom helpers
import MebeWeb.Utils, only: [get_author: 1, slugify: 1, unslugify_author: 1]
# DateTime functionality
alias Calendar.DateTime
import Calendar.Strftime
end
end