From 9573776b610850c38850fdd92df8727c80b0e39b Mon Sep 17 00:00:00 2001 From: f Date: Mon, 9 Oct 2017 19:29:31 -0300 Subject: [PATCH] cambiar el archivo y metadatos --- lib/sutty/models/post.rb | 69 ++++++++++++++++++++++++++---- lib/sutty/post.rb | 11 ++++- public/stylesheets/sass/sutty.scss | 5 +++ public/stylesheets/sutty.css | 2 +- public/stylesheets/sutty.css.map | 2 +- views/posts/_form.haml | 16 ++++++- 6 files changed, 91 insertions(+), 14 deletions(-) diff --git a/lib/sutty/models/post.rb b/lib/sutty/models/post.rb index afaa246f..916605f0 100644 --- a/lib/sutty/models/post.rb +++ b/lib/sutty/models/post.rb @@ -1,39 +1,84 @@ # frozen_string_literal: true require 'yaml' +require 'jekyll/utils' module Sutty module Models # Un post class Post attr_accessor :content, :front_matter - attr_reader :post, :site + attr_reader :post, :site, :errors REJECT_FROM_DATA = %w[excerpt slug draft date ext].freeze - def initialize(site, post = nil) + def initialize(site, post = nil, front_matter = {}) @site = site @post = post + @errors = [] + @front_matter = front_matter + + load_data! end def new? - !@post.is_a? Jekyll::Document + !@post.is_a? ::Jekyll::Document end + # Guarda los cambios def save - front_matter_from_data! + merge_data_with_front_matter! clean_content! - return unless write.zero? + return unless write + return unless detect_file_rename! + # Vuelve a leer el post para tomar los cambios @post.read true end private - def front_matter_from_data! - @front_matter ||= @post.data.reject do |key, _| + # Cambiar el nombre del archivo si cambió el título o la fecha. + # Como Jekyll no tiene métodos para modificar un Document, lo + # engañamos eliminando la instancia de @post y recargando otra. + def detect_file_rename! + basename = basename_from_front_matter + path = File.join(File.dirname(@post.path), basename) + + return true if basename == @post.basename + + if File.exist? path + @errors << 'El archivo destino ya existe' + return + end + + FileUtils.mv @post.path, path + replace_post! path + end + + def replace_post!(path) + opts = { site: @site, collection: @site.posts } + @site.posts.docs.delete @post + @post = ::Jekyll::Document.new(path, opts) + @site.posts.docs << @post + @site.posts.docs.sort! + end + + def basename_from_front_matter + date = @front_matter[:date].strftime('%F') + title = ::Jekyll::Utils.slugify(@front_matter[:title]) + + "#{date}-#{title}.markdown" + end + + def merge_data_with_front_matter! + @data.merge! Hash[@front_matter.map { |k, v| [k.to_s, v] }] + end + + def load_data! + @data ||= @post.data.reject do |key, _| REJECT_FROM_DATA.include? key end end @@ -43,8 +88,9 @@ module Sutty @content = @content.delete("\r") end + # Guarda los cambios en el archivo destino def write - File.open(@post.path, File::RDWR | File::CREAT, 0o640) do |f| + r = File.open(@post.path, File::RDWR | File::CREAT, 0o640) do |f| # Bloquear el archivo para que no sea accedido por otro # proceso u otra editora f.flock(File::LOCK_EX) @@ -59,10 +105,15 @@ module Sutty f.flush f.truncate(f.pos) end + + return true if r.zero? + + @errors << 'No se pudo escribir el archivo' + false end def full_content - "#{@front_matter.to_yaml}---\n\n#{@content}" + "#{@data.to_yaml}---\n\n#{@content}" end end end diff --git a/lib/sutty/post.rb b/lib/sutty/post.rb index 1e603236..e797c25f 100644 --- a/lib/sutty/post.rb +++ b/lib/sutty/post.rb @@ -47,12 +47,19 @@ module Sutty end post do - post = Sutty::Models::Post.new(@site, @post) + front_matter = { + tags: params[:post][:tags].split(',').map(&:strip), + categories: params[:post][:categories].split(',').map(&:strip), + title: params[:post][:title], + date: Time.new(params[:post][:date]) + } + + post = Sutty::Models::Post.new(@site, @post, front_matter) post.content = params[:post][:content] if post.save flash[:success] = 'Artículo guardado con éxito' - redirect to("/sites/#{@site.name}/posts/#{@post.basename}") + redirect to("/sites/#{@site.name}/posts/#{post.post.basename}") else flash[:error] = 'Hubo un error al guardar el artículo' redirect back diff --git a/public/stylesheets/sass/sutty.scss b/public/stylesheets/sass/sutty.scss index c0cd8923..7f0a475c 100644 --- a/public/stylesheets/sass/sutty.scss +++ b/public/stylesheets/sass/sutty.scss @@ -29,3 +29,8 @@ body { line-height: $footer-height; text-align: center; } + +textarea.post-content { + min-height: 80vh; + font-family: monospace; +} diff --git a/public/stylesheets/sutty.css b/public/stylesheets/sutty.css index e7ff2da7..aae885fa 100644 --- a/public/stylesheets/sutty.css +++ b/public/stylesheets/sutty.css @@ -1,2 +1,2 @@ -.background-cover{background:url(/assets/img/background.jpg) no-repeat center center fixed;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;background-size:cover}.full-height{height:calc(100vh - 60px)}html{position:relative;min-height:100%}body{margin-bottom:60px}.footer{position:absolute;bottom:0;width:100%;height:60px;line-height:60px;text-align:center} +.background-cover{background:url(/assets/img/background.jpg) no-repeat center center fixed;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;background-size:cover}.full-height{height:calc(100vh - 60px)}html{position:relative;min-height:100%}body{margin-bottom:60px}.footer{position:absolute;bottom:0;width:100%;height:60px;line-height:60px;text-align:center}textarea.post-content{min-height:80vh;font-family:monospace} /*# sourceMappingURL=sutty.css.map */ diff --git a/public/stylesheets/sutty.css.map b/public/stylesheets/sutty.css.map index 717a1914..7f185c55 100644 --- a/public/stylesheets/sutty.css.map +++ b/public/stylesheets/sutty.css.map @@ -1,6 +1,6 @@ { "version": 3, -"mappings": "AAEA,iBAAkB,CAChB,UAAU,CAAE,6DAA6D,CACzE,uBAAuB,CAAE,KAAK,CAC9B,oBAAoB,CAAE,KAAK,CAC3B,kBAAkB,CAAE,KAAK,CACzB,eAAe,CAAE,KAAK,CAGxB,YAAa,CACX,MAAM,CAAE,kBAA+B,CAGzC,IAAK,CACH,QAAQ,CAAE,QAAQ,CAClB,UAAU,CAAE,IAAI,CAGlB,IAAK,CACH,aAAa,CApBC,IAAI,CAuBpB,OAAQ,CACN,QAAQ,CAAE,QAAQ,CAClB,MAAM,CAAE,CAAC,CACT,KAAK,CAAE,IAAI,CACX,MAAM,CA3BQ,IAAI,CA4BlB,WAAW,CA5BG,IAAI,CA6BlB,UAAU,CAAE,MAAM", +"mappings": "AAEA,iBAAkB,CAChB,UAAU,CAAE,6DAA6D,CACzE,uBAAuB,CAAE,KAAK,CAC9B,oBAAoB,CAAE,KAAK,CAC3B,kBAAkB,CAAE,KAAK,CACzB,eAAe,CAAE,KAAK,CAGxB,YAAa,CACX,MAAM,CAAE,kBAA+B,CAGzC,IAAK,CACH,QAAQ,CAAE,QAAQ,CAClB,UAAU,CAAE,IAAI,CAGlB,IAAK,CACH,aAAa,CApBC,IAAI,CAuBpB,OAAQ,CACN,QAAQ,CAAE,QAAQ,CAClB,MAAM,CAAE,CAAC,CACT,KAAK,CAAE,IAAI,CACX,MAAM,CA3BQ,IAAI,CA4BlB,WAAW,CA5BG,IAAI,CA6BlB,UAAU,CAAE,MAAM,CAGpB,qBAAsB,CACpB,UAAU,CAAE,IAAI,CAChB,WAAW,CAAE,SAAS", "sources": ["sass/sutty.scss"], "names": [], "file": "sutty.css" diff --git a/views/posts/_form.haml b/views/posts/_form.haml index 37f1a42c..5dcca2b3 100644 --- a/views/posts/_form.haml +++ b/views/posts/_form.haml @@ -2,5 +2,19 @@ .form-group %button.btn.btn-success{type: 'submit'} Guardar .form-group - %textarea.form-control{name: 'post[content]', id: 'contents', autofocus: true} + %textarea.form-control.post-content{name: 'post[content]', id: 'contents', autofocus: true} = @post.content + .form-group + %label{for: 'date'} Fecha de publicación + %input.form-control{type: 'text', name: 'post[date]', id: 'date', value: @post.data['date']} + .form-group + %label{for: 'title'} Título + %input.form-control{type: 'text', name: 'post[title]', id: 'title', value: @post.data['title']} + .form-group + %label{for: 'tags'} Etiquetas + %input.form-control{type: 'text', name: 'post[tags]', id: 'tags', value: @post.data['tags'].join(',')} + %small.form-text.text-muted Separadas por comas + .form-group + %label{for: 'categories'} Categorías + %input.form-control{type: 'text', name: 'post[categories]', id: 'categories', value: @post.data['categories'].join(',')} + %small.form-text.text-muted Separadas por comas