require "big" IMGS_PER_PAGE = 5 UPLOAD_URL_PREFIX = "/uploads" STATIC_DIRS = ["/css", "/js", "/img", "/favicon.ico"] def requesting_static_file(env) request_path_startswith env, STATIC_DIRS end macro layout(name) base_url = Config.current.base_url begin is_admin = false if token = env.session.string? "token" is_admin = @context.storage.verify_admin token end page = {{name}} render "src/views/#{{{name}}}.html.ecr", "src/views/layout.html.ecr" rescue e message = e.to_s @context.error message render "src/views/message.html.ecr", "src/views/layout.html.ecr" end end macro send_img(env, img) send_file {{env}}, {{img}}.data, {{img}}.mime end macro get_username(env) # if the request gets here, it has gone through the auth handler, and # we can be sure that a valid token exists, so we can use not_nil! here token = env.session.string "token" (@context.storage.verify_token token).not_nil! end def send_json(env, json) env.response.content_type = "application/json" env.response.print json end def send_attachment(env, path) send_file env, path, filename: File.basename(path), disposition: "attachment" end def hash_to_query(hash) hash.map { |k, v| "#{k}=#{v}" }.join("&") end def request_path_startswith(env, ary) ary.each do |prefix| if env.request.path.starts_with? prefix return true end end false end def is_numeric(str) /^\d+/.match(str) != nil end def split_by_alphanumeric(str) arr = [] of String str.scan(/([^\d\n\r]*)(\d*)([^\d\n\r]*)/) do |match| arr += match.captures.select { |s| s != "" } end arr end def compare_alphanumerically(c, d) is_c_bigger = c.size <=> d.size if c.size > d.size d += [nil] * (c.size - d.size) elsif c.size < d.size c += [nil] * (d.size - c.size) end c.zip(d) do |a, b| return -1 if a.nil? return 1 if b.nil? if is_numeric(a) && is_numeric(b) compare = a.to_big_i <=> b.to_big_i return compare if compare != 0 else compare = a <=> b return compare if compare != 0 end end is_c_bigger end def compare_alphanumerically(a : String, b : String) compare_alphanumerically split_by_alphanumeric(a), split_by_alphanumeric(b) end def validate_archive(path : String) : Exception? file = ArchiveFile.new path file.check file.close return rescue e e end def random_str UUID.random.to_s.gsub "-", "" end def redirect(env, path) base = Config.current.base_url env.redirect File.join base, path end def validate_username(username) if username.size < 3 raise "Username should contain at least 3 characters" end if (username =~ /^[A-Za-z0-9_]+$/).nil? raise "Username should contain alphanumeric characters " \ "and underscores only" end end def validate_password(password) if password.size < 6 raise "Password should contain at least 6 characters" end if (password =~ /^[[:ascii:]]+$/).nil? raise "password should contain ASCII characters only" end end macro render_xml(path) base_url = Config.current.base_url send_file env, ECR.render({{path}}).to_slice, "application/xml" end macro render_component(filename) render "src/views/components/#{{{filename}}}.html.ecr" end # Works in all Unix systems. Follows https://github.com/crystal-lang/crystal/ # blob/master/src/crystal/system/unix/file_info.cr#L42-L48 def ctime(file_path : String) : Time res = LibC.stat(file_path, out stat) raise "Unable to get ctime of file #{file_path}" if res != 0 {% if flag?(:darwin) %} Time.new stat.st_ctimespec, Time::Location::UTC {% else %} Time.new stat.st_ctim, Time::Location::UTC {% end %} end def register_mime_types { ".zip" => "application/zip", ".rar" => "application/x-rar-compressed", ".cbz" => "application/vnd.comicbook+zip", ".cbr" => "application/vnd.comicbook-rar", }.each do |k, v| MIME.register k, v end end