major update
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
oDinZu 2022-10-15 18:28:57 -04:00
parent 7e9dd693a6
commit cf93d55f31
57 changed files with 1727 additions and 685 deletions

View File

@ -32,6 +32,8 @@ steps:
from_secret: server_pass
API_TOKEN:
from_secret: api_token
STRIPE_LIVE_KEY:
from_secret: stripe_live_key
privileged: false
volumes:
- name: jekyll

View File

@ -18,7 +18,7 @@
# We are open to granting a more permissive (such as MIT or Apache 2.0) license to SharpeTronics, Inc.
# software on a *case-by-case* basis, for an agreed upon price. Please contact
# info@sharpetronics.com if you are interested.
# info@sharpetronics.com.
# If you would like to contribute to this code, please follow GPLv3 guidelines.
# as an example, after making changes to the software (Called a Fork) and credit the original copyright holder as the creator with your credit added to theirs.

27
Gemfile
View File

@ -17,19 +17,22 @@ gem "jekyll", "~> 4.2.2"
# If you have any plugins, put them here!
group :jekyll_plugins do
gem "webrick", "~> 1.7" # dep for Jekyll 4.2.2; Ruby 3 doesn't have webrick by default anymore.
gem "json", "~> 2.1" # dep for json
gem "faraday" # a simple, but flexible HTTP client library, with support for multiple backends.
gem "httpx" # swiss army knife of Ruby for HTTP
gem 'faraday-multipart' # send with UDP; No encoding of the data
#gem 'faraday-http-cache' # caching may be an upgrade at later date if needed
gem "jekyll-feed", "~> 0.12"
gem "jekyll-menus"
gem "jekyll-tagging"
gem "jekyll-archives"
gem "jekyll-paginate-v2"
gem 'jekyll-feed', '~> 0.12'
gem 'jekyll-menus'
gem 'jekyll-tagging'
gem 'jekyll-archives'
gem 'jekyll-paginate-v2'
end
group :dev_plugins do
gem 'webrick', '~> 1.7' # dep for Jekyll 4.2.2; Ruby 3 doesn't have webrick by default anymore.
gem 'json', '~> 2.1' # dep for json
gem 'faraday' # a simple, but flexible HTTP client library, with support for multiple backends.
gem 'httpx' # swiss army knife of Ruby for HTTP
gem 'faraday-multipart' # send with UDP; No encoding of the data
gem 'stripe' # integrating Stripe payments with Jekyll
gem 'rails' # must use Rails for .blank support
#gem 'faraday-http-cache' # caching may be an upgrade at later date
end
# Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem

View File

@ -1,13 +1,71 @@
GEM
remote: https://rubygems.org/
specs:
actioncable (6.0.6)
actionpack (= 6.0.6)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailbox (6.0.6)
actionpack (= 6.0.6)
activejob (= 6.0.6)
activerecord (= 6.0.6)
activestorage (= 6.0.6)
activesupport (= 6.0.6)
mail (>= 2.7.1)
actionmailer (6.0.6)
actionpack (= 6.0.6)
actionview (= 6.0.6)
activejob (= 6.0.6)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (6.0.6)
actionview (= 6.0.6)
activesupport (= 6.0.6)
rack (~> 2.0, >= 2.0.8)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
actiontext (6.0.6)
actionpack (= 6.0.6)
activerecord (= 6.0.6)
activestorage (= 6.0.6)
activesupport (= 6.0.6)
nokogiri (>= 1.8.5)
actionview (6.0.6)
activesupport (= 6.0.6)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
activejob (6.0.6)
activesupport (= 6.0.6)
globalid (>= 0.3.6)
activemodel (6.0.6)
activesupport (= 6.0.6)
activerecord (6.0.6)
activemodel (= 6.0.6)
activesupport (= 6.0.6)
activestorage (6.0.6)
actionpack (= 6.0.6)
activejob (= 6.0.6)
activerecord (= 6.0.6)
marcel (~> 1.0)
activesupport (6.0.6)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
zeitwerk (~> 2.2, >= 2.2.2)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
builder (3.2.4)
colorator (1.1.0)
concurrent-ruby (1.1.10)
crass (1.0.6)
em-websocket (0.5.3)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0)
erubi (1.11.0)
eventmachine (1.2.7)
faraday (2.3.0)
faraday-net_http (~> 2.0)
@ -17,6 +75,8 @@ GEM
faraday-net_http (2.0.3)
ffi (1.15.5)
forwardable-extended (2.6.0)
globalid (1.0.0)
activesupport (>= 5.0)
http-2-next (0.5.0)
http_parser.rb (0.6.0)
httpx (0.20.3)
@ -61,12 +121,55 @@ GEM
listen (3.7.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
loofah (2.19.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
mini_mime (>= 0.1.1)
marcel (1.0.2)
mercenary (0.4.0)
method_source (1.0.0)
mini_mime (1.1.2)
minitest (5.16.3)
multipart-post (2.2.3)
nio4r (2.5.8)
nokogiri (1.13.8-x86_64-linux)
racc (~> 1.4)
nuggets (1.6.0)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
public_suffix (4.0.7)
racc (1.6.0)
rack (2.2.4)
rack-test (2.0.2)
rack (>= 1.3)
rails (6.0.6)
actioncable (= 6.0.6)
actionmailbox (= 6.0.6)
actionmailer (= 6.0.6)
actionpack (= 6.0.6)
actiontext (= 6.0.6)
actionview (= 6.0.6)
activejob (= 6.0.6)
activemodel (= 6.0.6)
activerecord (= 6.0.6)
activestorage (= 6.0.6)
activesupport (= 6.0.6)
bundler (>= 1.3.0)
railties (= 6.0.6)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.4.3)
loofah (~> 2.3)
railties (6.0.6)
actionpack (= 6.0.6)
activesupport (= 6.0.6)
method_source
rake (>= 0.8.7)
thor (>= 0.20.3, < 2.0)
rake (13.0.6)
rb-fsevent (0.11.1)
rb-inotify (0.10.1)
ffi (~> 1.0)
@ -76,8 +179,17 @@ GEM
safe_yaml (1.0.5)
sassc (2.4.0)
ffi (~> 1.9)
sprockets (4.1.1)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.4.2)
actionpack (>= 5.2)
activesupport (>= 5.2)
sprockets (>= 3.0.0)
stripe (7.1.0)
terminal-table (2.0.0)
unicode-display_width (~> 1.1, >= 1.1.1)
thor (1.2.1)
thread_safe (0.3.6)
tzinfo (1.2.9)
thread_safe (~> 0.1)
@ -86,6 +198,10 @@ GEM
unicode-display_width (1.8.0)
wdm (0.1.1)
webrick (1.7.0)
websocket-driver (0.7.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
zeitwerk (2.6.0)
PLATFORMS
x86_64-linux-musl
@ -101,6 +217,8 @@ DEPENDENCIES
jekyll-paginate-v2
jekyll-tagging
json (~> 2.1)
rails
stripe
tzinfo (~> 1.2)
tzinfo-data
wdm (~> 0.1.1)

View File

@ -1,4 +1,4 @@
# This software gathers all collection types from an API and saves that data into Jekyll _data/ folder.
# This software is coded in Ruby and gathers all collection types from an API and saves that data into the Jekyll _data/.. folder; a including, secure integration that allows for Ecommerce with Stripe.
# Copyright (C) SharpeTronics, Inc. 2013-2023
# Author(s): Charles Sharpe(@odinzu_me)
@ -19,7 +19,7 @@
# We are open to granting a more permissive (such as MIT or Apache 2.0) license to SharpeTronics, Inc.
# software on a *case-by-case* basis, for an agreed upon price. Please contact
# info@sharpetronics.com if you are interested.
# info@sharpetronics.com.
# If you would like to contribute to this code, please follow GPLv3 guidelines.
# as an example, after making changes to the software (Called a Fork) and credit the original copyright holder as the creator with your credit added to theirs.

View File

@ -17,10 +17,10 @@ No proprietary operating system dependencies required, only Docker Engine super
* SharpeTronics Pages ready (free static hosting).
* Drone CI / CD system.
* Backups for restoring to previous states.
* Headless CMS with superpowers!
* Headless CMS with Strapi superpowers!
* Ease of use for editors and writers.
* Distributed CDN with automatic HTTPS (Cloudflare).
* Secure ecommerce shopping.
* Secure Ecommerce shopping with Stripe.
* International Multi-language
# Jekyll Plugins
@ -59,8 +59,8 @@ No proprietary operating system dependencies required, only Docker Engine super
* Stripe https://stripe.com/docs
* SharpeTronics Custom Ruby Plugin (License: GPLv3)
## Socials
## Socials
* Discord: https://discord.gg/TUZ6P7BV
* Twitter: https://nitter.privacydev.net/sharpetronics
* Twitter: https://twitter.com/sharpetronics
* Email: info@sharpetronics.com
* Telegram: https://t.me/+oFUwKSn3frgzZDFh
* Telegram: https://t.me/+oFUwKSn3frgzZDFh

View File

@ -49,31 +49,36 @@ feed:
- legal
- devops
# ===================================================================================
# teh API dashboard configuration
api:
# Your API endpoint
# ecommerce integration with Stripe
stripe:
# The Stripe Jekyll configuration
enabled: true # sometimes we don't need ecommerce integration; defaults to false
reset_stripe_db: false # when set true, it will delete all remote Stripe products and resubmit the products from CMS interface; caution! used for cleaning a Stripe db.
# uri format: [endpoint]+[endpoint_ext]+[endpoint_param]
endpoint: https://dash.sharpetronics.com # url to api; no trailing slash
endpoint_ext: /api/ # (optional) the extension of endpoint e.g. https://www.example.com/api/
endpoint_query: ?populate=* # (optional) e.g. force retrieve all json data
output: true # when true (global), new or modified images are downloaded from each collection type
local_media_dir: uploads/ # a placeholder example
endpoint_param: ?populate=* # (optional) e.g. populate all json data; does not affect endpoint_uploads.
endpoint_uploads: uploads # optional, no use at the moment; the location of all media files on api; this is required for downloading images
local_media_dir: uploads/ # where to cache the images
cache_images: true # when true (global), new or modified images are downloaded from endpoint_uploads; note: Docker is also caching downloaded images.
collections:
# Example for a "posts" collection
posts: # required
# Collection name used to construct the url requested. Example: type `foo` would generate the following url `http://localhost:1337/foo`.
type: posts # used for directory creation and organizing files
filepath: '_data/posts/index.json' # a placeholder example
# Permalink used to generate the output files (eg. /posts/:id).
# permalink: /blog/:id/
# output: false
# Example for a "products" collection
#products:
# Collection name (optional). Used to construct the url requested. Example: type `foo` would generate the following url `http://localhost:1337/foo`.
#type: products # a placeholder example
#path: '_data/products/index.json' # a placeholder example
# Permalink used to generate the output files (eg. /posts/:id).
# permalink: /blog/:id/
# output: false
# the "posts" collection
posts: # required
# Collection name used to construct the url requested. Example: type `foo` would generate the following url `http://localhost:1337/foo`.
type: posts # required; used for directory creation and organizing files
filepath: '_data/posts/index.json' # the filepath for posts json hash
# the "products" collection
products: # optional?
# Collection name (optional). Used to construct the url requested. Example: type `foo` would generate the following url `http://localhost:1337/foo`.
type: products # required; used for directory creation and organizing files
filepath: '_data/products/index.json' # the filepath for products json hash
# ===================================================================================
# Collection configuration
# These collections will sort types of products and loop through that
@ -83,7 +88,7 @@ collections_dir: collections
collections:
products:
output: true
output: true # true or false
permalink: /products/:path/
permalink: "/blog/:categories/:year/:month/:day/:title/" # Built in options include: date, pretty, ordinal, weekdate, none; learn more here: https://jekyllrb.com/docs/permalinks/
@ -104,7 +109,6 @@ sass:
# Site configuration for the Jekyll v2 Pagination gem
pagination:
# Site-wide kill switch, disabled here it doesn't run at all
enabled: true
# Set to 'true' to enable pagination debugging. This can be enabled in the site config or only for individual pagination pages
@ -114,7 +118,7 @@ pagination:
# How many objects per paginated page, used to be `paginate` (default: 0, means all)
per_page: 9
# The permalink structure for the paginated pages (this can be any level deep)
permalink: '/:num/' # Pages are index.html inside this folder (default)
permalink: ':num/' # Pages are index.html inside this folder (default)
#permalink: '/page/:num.html' # Pages are simple html files
#permalink: '/page/:num' # Pages are html files, linked jekyll extensionless permalink style.

View File

@ -5,8 +5,8 @@ Charles:
last_name: "Sharpe"
site: "https://www.csharpe.me"
avatar: "/uploads/authors/c-avatar.webp" #Size of avatar_image 36x36
bio: "Independent Full-Stack Web Developer; curious about Astronomy, Information Technology, Privacy, Permaculture, Philosophy & Consciousness."
email: "charles.sharpee@gmail.com"
bio: "A Stack Architect; curious about Astronomy, Information Technology, Privacy, Permaculture, Philosophy & Consciousness."
email: "info@sharpetronics.com"
# Twitter nick for use in Twitter cards and follow button.
twitter: "csharpe_me" # if no twitter in this config, the twitter follow button will be removed
# GitHub nick for use in follow button in author block.
@ -14,12 +14,8 @@ Charles:
social:
- title: "github"
url: "https://github.com/csharpee"
- title: "linkedin"
url: "https://www.linkedin.com/in/EXAMPLE"
- title: "youtube"
url: "https://www.youtube.com/channel/EXAMPLE"
- title: "facebook"
url: "https://www.facebook.com/EXAMPLE"
- title: "twitter"
url: "https://www.twitter.com/odinzu_me"
Dexter:

File diff suppressed because one or more lines are too long

View File

@ -1,15 +0,0 @@
title: Cup
url: /products/2020-06-03-cup/
id: 201806
sku: 202055478373
image: assets/images/Peppermint-Lip-Balm.jpg
description: Our all natural Peppermint lip balm was a great hit with our family & friends. We hope you enjoy it too!
excerpt: Our BEST SELLING lip balm - you'll love it!
category: Lip Balm
tag: Health
quantity: 14
price: 125.00
weight: Peppermint
format: Physical
material: Wood, Steel
dimension: 15in x 35in

File diff suppressed because one or more lines are too long

View File

@ -1,15 +0,0 @@
title: Dragon
url: /products/2017-02-03-dragon/
id: 201806
sku: 202055478373
image: assets/images/Peppermint-Lip-Balm.jpg
description: Our all natural Peppermint lip balm was a great hit with our family & friends. We hope you enjoy it too!
excerpt: Our BEST SELLING lip balm - you'll love it!
category: Lip Balm
tag: Health
quantity: 14
price: 5.00
weight: Peppermint
format: Physical
material: Wood, Steel
dimension: 15in x 35in

View File

@ -9,18 +9,20 @@ pagination:
<section id="main" class="wrapper style1">
<div class="inner">
<!-- Shopping Cart -->
{% unless page.layout == "posts" %}
<!-- The back button on a single post -->
<section class="row product-cart journal">
<div class="col-12">
<a href="{{site.url}}/blog"><h5 class="button back">< Go Back</h5></a>
</div>
</section>
</section>
{% endunless %}
<!-- Title -->
<header class="major special journal">
<div class="hero"> <img class="image fit" src="{{ page.banner_image }}" alt="{{ page.banner_image_alt }}"> </div>
<h1>{{ page.title }}</h1>
<p>{{ page.sub_title }}</p>
<p>{{ page.subheading }}</p>
</header>
<!-- Content -->
<div class="content">

View File

@ -16,7 +16,7 @@ layout: post
<div class="title">
<h2><a href="{{ post.url | absolute_url }}">{{ post.title }}</a></h2>
<p>{{ post.sub_heading }}</p>
<p>{{ post.subheading }}</p>
</div>
{% assign author = site.data.authors[post.author] %}
{%- include author_card.html -%}
@ -30,7 +30,7 @@ layout: post
<li><b>{{ post.category }}</b></li>
<li><b>Tags: </b>{{ post.tags }}</li>
<!-- <li class="icon solid fa-heart">144</li> -->
<li><a href="{{ post.url | absolute_url }}" class="icon solid fa-comment">88</a></li>
<li><a href="{{ post.url | absolute_url }}" class="icon solid fa-comment">43</a></li>
</ul>
</footer>
</article>

View File

@ -26,7 +26,7 @@ pagination:
<!-- Page Heading -->
<header class="major special">
<h1>{{ page.title }}</h1>
<p>{{ page.sub_heading }}</p>
<p>{{ page.subheading }}</p>
</header>
<!-- Main Body Content -->
<div class="content">

View File

@ -1,9 +1,9 @@
# This software gathers all collection types from an API and saves that data into Jekyll _data/ folder.
# This software gathers all collection types from an API or headless CMS, then saves that data into the Jekyll _data/ folder.
# Copyright (C) SharpeTronics, Inc. 2013-2023
# Author(s): Charles Sharpe(@odinzu_me)
# Author(s): Charles Sharpe(@odinzu_me) aka SharpeTronics, Inc.
# License: GPLv3
# Version: 1
# Version: 1.3
# This is Free Software released under GPLv3. Any misuse of this software
# will be followed up with GPL enforcement via Software Freedom Law Center:
@ -18,8 +18,8 @@
# Dependencies downloaded as part of the build process may be covered by other open-source licenses.
# We are open to granting a more permissive (such as MIT or Apache 2.0) license to SharpeTronics, Inc.
# software on a *case-by-case* basis, for an agreed upon price. Please contact
# info@sharpetronics.com if you are interested.
# software on a *case-by-case* basis, for an agreed upon price. Please email
# info@sharpetronics.com.
# If you would like to contribute to this code, please follow GPLv3 guidelines.
# as an example, after making changes to the software (Called a Fork) and credit the original copyright holder as the creator with your credit added to theirs.
@ -31,34 +31,24 @@ require 'faraday' # https://lostisland.github.io/faraday/usage/
require 'httpx/adapters/faraday' # https://honeyryderchuck.gitlab.io/httpx/
require 'addressable/uri' # https://github.com/sporkmonger/addressable If you need to normalize URIs, e.g. http://www.詹姆斯.com/
require 'faraday/multipart' # https://github.com/lostisland/faraday-multipart
require 'active_support/core_ext/object/blank' # load only the specific extension for .blank? support
Jekyll.logger.debug "A Ruby bot be building this...[*_-]\n".green.bold
Jekyll.logger.debug "A SharpeTronics bot be building this...[*_-]\n".green.bold
# prepare uri & load _config.yml into config_yml object
config_yml = "_config.yml"
f = YAML.load(File.read(config_yml.to_s)) # r - read file
api_endpoint = f['api']['endpoint']
endpoint_query = f['api']['endpoint_query']
endpoint_param = f['api']['endpoint_param']
endpoint_ext = f['api']['endpoint_ext']
Jekyll.logger.debug "DEBUG: API_ENDPDOINT for GET COLLECTIONS: " "#{api_endpoint}".to_s.yellow.bold
# create directory _data/posts/ if doesn't exist
if not Dir.exist?(f['api']['collections']['posts']['type'].to_s)
puts "folder does not exist, let's create a new folder in Jekyll called: _data/posts/ ".yellow
Dir.mkdir (f['api']['collections']['posts']['type'].to_s)
end
# create file.json if doesn't exist
if not File.exist?(f['api']['collections']['posts']['filepath'])
puts "file does not exist, let's create a new file".yellow.bold
File.write(f['api']['collections']['posts']['filepath'], 'A Ruby bot be building this...[*_-]\n')
end
# authenticated or public API data
# import API_TOKEN from the environment. e.g. export API_TOKEN=example
api_token = ENV['API_TOKEN']
# check if api_token is auth or unauth
if api_token === nil
if "#{api_token}".blank?
# logs data to screen
puts "ENV DEBUG: API_TOKEN FAILED! Testing a public request without a bearer token... ".red
puts "TOKEN MISSING! Testing a public request without a bearer token... ".red
options = {
headers: ""
}
@ -80,34 +70,55 @@ if api_token === nil
Jekyll.logger.debug "HTTP DEBUG: BULIDING CONNECTION: #{api_builder}".to_s.yellow.bold
# logs auth status to screen
puts ""
puts "API_TOKEN SUCCESS! Getting the authenticated data...".green
puts "API_DATABASE TOKEN SUCCESS! Getting the authenticated data...".cyan.bold
puts ""
end # close if/else
# TODO: add ['products'] collection
# parses through local Jekyll _config.yml file and gets collection `type`
#products_path = "[:site].config['api']['collections']['products']['type']"
posts_path = f['api']['collections']['posts']['type']
Jekyll.logger.debug "CONFIG DEBUG: JEKYLL CONFIG TYPE PATH: " "#{posts_path}".to_s.yellow.bold
products_type = f['api']['collections']['products']['type']
Jekyll.logger.debug "CONFIG DEBUG: JEKYLL CONFIG PRODUCTS PATH: " "#{products_type}".to_s.yellow
# populate all data to have image data available in Strapi
# TODO: update this to work with any URL API in _config.yml; e.g. some API's don't need static /api like Strapi CMS
uri = "#{api_endpoint}#{endpoint_ext}#{posts_path}#{endpoint_query}"
Jekyll.logger.debug "HTTP DEBUG: URI: " "#{uri}".to_s.yellow
posts_type = f['api']['collections']['posts']['type']
Jekyll.logger.debug "CONFIG DEBUG: JEKYLL CONFIG POSTS PATH: " "#{posts_type}".to_s.yellow.bold
# the actual GET with header data; retrieve all json data from API
api_connect = api_builder.get(uri)
Jekyll.logger.debug "HTTP DEBUG: THE COLLECTION IS: #{posts_path} WITH STATUS CODE: #{api_connect.status}".to_s.yellow.bold
# store filepath config options
posts_filepath = f['api']['collections']['posts']['filepath']
Jekyll.logger.debug "CONFIG DEBUG: JEKYLL CONFIG POSTS FILEPATH: " "#{posts_filepath}".to_s.yellow.bold
# api request variable passing uri and storing inside response var
# response = api_request(uri)
json_data = api_connect.body
Jekyll.logger.debug "HTTP DEBUG: IS JSON DATA EMPTY? #{json_data.empty?}".to_s.yellow
#Jekyll.logger.debug "DEBUG: STOUT JSON DATA: #{json_data}".to_s.yellow.bold
products_filepath = f['api']['collections']['products']['filepath']
Jekyll.logger.debug "CONFIG DEBUG: JEKYLL CONFIG PRODUCTS FILEPATH: " "#{products_filepath}".to_s.yellow
# opens the file and writes the data to the file
Jekyll.logger.debug "WRITING RAW JSON DATA TO FILE...".yellow.bold
File.write('./_data/posts/index.json', JSON.dump(json_data))
# build the resource link & populate posts json data
uri_posts = "#{api_endpoint}#{endpoint_ext}#{posts_type}#{endpoint_param}"
Jekyll.logger.debug "HTTP DEBUG: POSTS URI: " "#{uri_posts}".to_s.yellow.bold
# build the resource link & populate posts json data
uri_products = "#{api_endpoint}#{endpoint_ext}#{products_type}#{endpoint_param}"
Jekyll.logger.debug "HTTP DEBUG: PRODUCTS URI: " "#{uri_products}".to_s.yellow
# the actual GET with header data; retrieve all product and posts json data from API
posts_api_connect = api_builder.get(uri_posts)
Jekyll.logger.debug "HTTP DEBUG: THE COLLECTION is: #{posts_type} with STATUS CODE: #{posts_api_connect.status}".to_s.cyan.bold
products_api_connect = api_builder.get(uri_products)
Jekyll.logger.debug "HTTP DEBUG: THE COLLECTION is: #{products_type} with STATUS CODE: #{products_api_connect.status}".to_s.cyan.bold
# store all data into the body of the api
posts_json_data = posts_api_connect.body
Jekyll.logger.debug "HTTP DEBUG: IS POST JSON DATA EMPTY? #{posts_json_data.empty?}".to_s.yellow
products_json_data = products_api_connect.body
Jekyll.logger.debug "HTTP DEBUG: IS PRODUCT JSON DATA EMPTY? #{products_json_data.empty?}".to_s.yellow
# opens the posts file and writes the data to the file
Jekyll.logger.debug "WRITING RAW POSTS JSON DATA TO FILE...".yellow.bold
File.write(posts_filepath, JSON.dump(posts_json_data))
puts ""
Jekyll.logger.debug "SUCCESS! JSON FILE DOWNLOADED...".green
Jekyll.logger.debug "SUCCESS! JSON POSTS FILE DOWNLOADED...".cyan.bold
puts ""
# opens the products file and writes the data to the file
Jekyll.logger.debug "WRITING RAW PRODUCTS JSON DATA TO FILE...".yellow.bold
File.write(products_filepath, JSON.dump(products_json_data))
puts ""
Jekyll.logger.debug "SUCCESS! JSON PRODUCTS FILE DOWNLOADED...".cyan.bold
puts ""

View File

@ -1,192 +0,0 @@
# This software gathers all collection types from an API and saves that data into Jekyll _data/ folder.
# Copyright (C) SharpeTronics, Inc. 2013-2023
# Author(s): Charles Sharpe(@odinzu_me)
# License: GPLv3
# Version: 1
# This is Free Software released under GPLv3. Any misuse of this software
# will be followed up with GPL enforcement via Software Freedom Law Center:
# https://www.softwarefreedom.org/
# If you incorporate or include any code from SharpeTronics, Inc., your
# code must be licensed as GPLv3 (not GPLv2 or MIT)
# The GPLv3 software license applies to the code directly included in this source distribution.
# See the LICENSE & COPYING file for full information.
# Dependencies downloaded as part of the build process may be covered by other open-source licenses.
# We are open to granting a more permissive (such as MIT or Apache 2.0) license to SharpeTronics, Inc.
# software on a *case-by-case* basis, for an agreed upon price. Please contact
# info@sharpetronics.com if you are interested.
# If you would like to contribute to this code, please follow GPLv3 guidelines.
# as an example, after making changes to the software (Called a Fork) and credit the original copyright holder as the creator with your credit added to theirs.
require 'fileutils' # https://ruby-doc.org/stdlib-2.4.1/libdoc/fileutils/rdoc/FileUtils.html
require 'json' # https://ruby-doc.org/stdlib-3.0.2/libdoc/json/rdoc/JSON.html
require 'yaml' # load jekyll yaml config
module Jekyll
# initialize variables
product_path = "collections/_products/"
post_path = "collections/_posts/"
file_ending = ".md"
# load _config.yml
config_yml = "_config.yml"
f = YAML.load(File.read(config_yml.to_s)) # r - read file
Jekyll.logger.debug "DOCUMENT DEBUG: Is config empty? " "#{config_yml.empty?}".to_s.yellow
# set filepath, load the json, then parse through json file in _data/posts/index.json
json_post_path = f['api']['collections']['posts']['filepath']
# must read data into memory before parsing file
read_json = File.read(json_post_path) # read json for all posts
#json_product_path = f['api']['collections']['products']['path']
# TODO: update for products also
parsed_file = JSON.parse(read_json.to_s) # returns a hash
# cache / check and download all collection post data
collection_ids = parsed_file["data"]
# loop through each collection id
collection_ids.each do |id|
#puts "#{id}".yellow # output collection id for debug
# store json specific data for each post
# check if title date is empty
if id["attributes"]["title"] === nil
Jekyll.logger.debug "ERROR: title is empty; does API post have title?".to_s.red
else
title = id["attributes"]["title"]
Jekyll.logger.debug "DOCUMENT DEBUG: Collection Title: " "#{title}".to_s.yellow.bold
end
# store slug into object
slug = id["attributes"]["slug"]
Jekyll.logger.debug "DOCUMENT DEBUG: Collection Slug: " "#{slug}".to_s.yellow
# check if sub_heading data is empty
if id["attributes"]["subheading"] === nil
Jekyll.logger.debug "ERROR: subheading is empty; does API post have subheading?".to_s.red
else
sub_heading = id["attributes"]["subheading"]
Jekyll.logger.debug "DOCUMENT DEBUG: Collection Subheading: " "#{sub_heading}".to_s.yellow.bold
end
# check if date data is empty
if id["attributes"]["date"] === nil
Jekyll.logger.debug "ERROR: date is empty; does API post have date?".to_s.red
else
date = id["attributes"]["date"]
Jekyll.logger.debug "DOCUMENT DEBUG: Collection Date: " "#{date}".to_s.yellow
end
# check if layout data is empty
if id["attributes"]["layout"] === nil
Jekyll.logger.debug "ERROR: layout is empty; does API post have layout?".to_s.red
else
layout = id["attributes"]["layout"]
Jekyll.logger.debug "DOCUMENT DEBUG: Collection Layout: " "#{layout}".to_s.yellow.bold
end
# check if author data is empty
puts "#{id}"
if "#{id["attributes"]["author"]}".empty? || nil
Jekyll.logger.debug "ERROR: author is empty; does API post have author?".to_s.red
else
author = id["attributes"]["author"]["data"]["attributes"]["name"]
Jekyll.logger.debug "DOCUMENT DEBUG: Collection Author: " "#{author}".to_s.yellow
end
# check if image data is empty
if "#{id["attributes"]["image"]}".empty? || nil || "#{id["attributes"]["image"]["data"]}".empty?
Jekyll.logger.debug "ERROR: banner_image url is empty; does API post have banner image url?".to_s.red
else
banner_image = id["attributes"]["image"]["data"]["attributes"]["url"]
Jekyll.logger.debug "DOCUMENT DEBUG: Collection Banner Image: " "#{banner_image}".to_s.yellow.bold
end
# check if banner_image_alt data is empty
if id["attributes"]["image_alt"] === nil
Jekyll.logger.debug "ERROR: banner_image_alt is empty; does API post have banner_image_alt?".to_s.red
else
banner_image_alt = id["attributes"]["image_alt"]
Jekyll.logger.debug "DOCUMENT DEBUG: Collection Banner Image Alt-text: " "#{banner_image_alt}".to_s.yellow
end
# check if tags data is empty
if "#{id["attributes"]["tags"]}".empty? || nil
Jekyll.logger.debug "ERROR: tags is empty; does API post have tags?".to_s.red
else
# an array for storing multiple input
tags = id["attributes"]["tags"]["data"]
# loop through all tags
tags.each do |tag|
puts ""
Jekyll.logger.debug "DOCUMENT DEBUG: Collection Tag(s): " "#{tag}".to_s.yellow
end
puts "" # pretty debug spacing
end
# check if category data is empty
if "#{id["attributes"]["category"]}".empty? || nil
Jekyll.logger.debug "ERROR: category is empty; does API post have a category?".to_s.red
else
category = id["attributes"]["category"]["data"]["attributes"]["name"]
Jekyll.logger.debug "DOCUMENT DEBUG: Collection Category: " "#{category}".to_s.yellow.bold
end
# check if content data is empty
if id["attributes"]["content"] === nil
Jekyll.logger.debug "ERROR: content is empty; does API post have content?".to_s.red
else
content = id["attributes"]["content"]
Jekyll.logger.debug "DOCUMENT DEBUG: Collection Raw Content: " "#{content}".to_s.yellow
end
# create the filename
file_name = "#{date}-#{slug}#{file_ending}"
# let us put humpty dumpty back together again!
# create a new collection type post *.md
p = File.open( "#{post_path}#{file_name}","w" )
# file content in Jekyll yaml formatting
p.puts "---"
p.puts "layout: #{layout}"
p.puts "date: #{date}"
p.puts "author: #{author}"
p.puts "banner_image: #{banner_image}" # the banner images are downloaded from API in image-filter.rb.
p.puts "banner_image_alt: #{banner_image_alt}"
p.puts "title: #{title}"
if sub_heading != nil
p.puts "sub_heading: #{sub_heading}"
end
# add tags without json formatting in pretty format
p.print "tags: " # pretty debug
if "#{id["attributes"]["tags"]}".empty? || nil
Jekyll.logger.debug "ERROR: tags is empty; does API post have tags?".to_s.red
else
tags = id["attributes"]["tags"]["data"]
# loop through all tags
tags.each do |tag|
p.print tag["attributes"]["tag"]
p.print ", "
end
p.puts "" # pretty debug spacing
end
if "#{id["attributes"]["category"]}".empty? || nil
Jekyll.logger.debug "ERROR: category is empty; does API post have a category?".to_s.red
else
category = id["attributes"]["category"]["data"]["attributes"]["name"]
p.puts "category: " "#{category}"
end
p.puts "---" # close .yaml file frontmatter
p.puts "#{content}" # write post content
p.close # close the file; stop writing
end
end

View File

@ -0,0 +1,203 @@
# This software generates mardown formatted posts from json data.
# Copyright (C) SharpeTronics, Inc. 2013-2023
# Author(s): Charles Sharpe(@odinzu_me) aka SharpeTronics, Inc.
# License: GPLv3
# Version: 1.3
# This is Free Software released under GPLv3. Any misuse of this software
# will be followed up with GPL enforcement via Software Freedom Law Center:
# https://www.softwarefreedom.org/
# If you incorporate or include any code from SharpeTronics, Inc., your
# code must be licensed as GPLv3 (not GPLv2 or MIT)
# The GPLv3 software license applies to the code directly included in this source distribution.
# See the LICENSE & COPYING file for full information.
# Dependencies downloaded as part of the build process may be covered by other open-source licenses.
# We are open to granting a more permissive (such as MIT or Apache 2.0) license to SharpeTronics, Inc.
# software on a *case-by-case* basis, for an agreed upon price. Please email
# info@sharpetronics.com.
# If you would like to contribute to this code, please follow GPLv3 guidelines.
# as an example, after making changes to the software (Called a Fork) and credit the original copyright holder as the creator with your credit added to theirs.
require 'fileutils' # https://ruby-doc.org/stdlib-2.4.1/libdoc/fileutils/rdoc/FileUtils.html
require 'json' # https://ruby-doc.org/stdlib-3.0.2/libdoc/json/rdoc/JSON.html
require 'yaml' # load Jekyll yaml config
require 'active_support/core_ext/object/blank' # load only the specific extension for .blank? support
module Jekyll
# initialize variables
jekyll_post_path = "collections/_posts/"
file_ending = ".md"
# searches for _config.yml file in the root / of the Jekyll project.
config_yml = "_config.yml"
f = YAML.load(File.read(config_yml.to_s)) # r - read file
Jekyll.logger.debug "::DOCUMENT POST DEBUG:: Is the _config.yml available? " "#{f}".to_s.magenta.bold
# set filepath, load the json, then parse through json file
json_post_path = f['api']['collections']['posts']['filepath']
# must read data into memory before parsing file
read_posts_json = File.read(json_post_path) # read json for all posts
# parse through json files
parsed_posts_file = JSON.parse(read_posts_json.to_s) # returns a hash
# cache / verify and download each post data
post_ids = parsed_posts_file["data"]
# loop through each post id
post_ids.each do |id|
# get post modify time; it is cached in the Jekyll container
updatedAt = id["attributes"]["updatedAt"]
# store json specific data for each post
# determine if heading is blank or null.
if "#{id["attributes"]["title"]}".blank? || "#{id["attributes"]["title"]}".empty?
Jekyll.logger.debug "ERROR: the post title is missing; does the post have a heading?".to_s.red
else
title = id["attributes"]["title"]
Jekyll.logger.debug "::DOCUMENT POST DEBUG:: Title: " "#{title}".to_s.yellow.bold
end
# store slug into object (object is auto generated with Strapi plugin)
slug = id["attributes"]["slug"]
Jekyll.logger.debug "::DOCUMENT POST DEBUG:: Slug: " "#{slug}".to_s.yellow
# determine if subheading is blank or null.
if "#{id["attributes"]["subheading"]}".blank?
Jekyll.logger.debug "ERROR: the subheading is missing; does post [" "#{title}] have a subheading?".to_s.red
else
subheading = id["attributes"]["subheading"]
Jekyll.logger.debug "::DOCUMENT POST DEBUG:: Subheading: " "#{subheading}".to_s.yellow.bold
end
# determine if date is blank or null.
if "#{id["attributes"]["date"]}".blank?
Jekyll.logger.debug "ERROR: the date is missing; does post [" "#{title}] have a date?".to_s.red
else
date = id["attributes"]["date"]
Jekyll.logger.debug "::DOCUMENT POST DEBUG:: Date: " "#{date}".to_s.yellow
end
# determine if layout is blank or null.
if "#{id["attributes"]["layout"]}".blank?
Jekyll.logger.debug "ERROR: the layout is missing; does post [" "#{title}] have a layout?".to_s.red
else
layout = id["attributes"]["layout"]
Jekyll.logger.debug "::DOCUMENT POST DEBUG:: Layout: " "#{layout}".to_s.yellow.bold
end
# determine if author data is blank or null.
if "#{id["attributes"]["author"]["data"]}".blank? || "#{id["attributes"]["author"]["data"]}".blank?
Jekyll.logger.debug "ERROR: the author is missing; does post [" "#{title}] have a author?".to_s.red
else
author = id["attributes"]["author"]["data"]["attributes"]["name"]
Jekyll.logger.debug "::DOCUMENT POST DEBUG:: Author: " "#{author}".to_s.yellow
end
# determine if banner_image is blank or null.
if "#{id["attributes"]["banner_image"]["data"]}".blank?
Jekyll.logger.debug "ERROR: the banner_image url is missing; does post [" "#{title}] have a banner image url?".to_s.red
else
banner_image = id["attributes"]["banner_image"]["data"]["attributes"]["url"]
Jekyll.logger.debug "::DOCUMENT POST DEBUG:: Banner image: " "#{banner_image}".to_s.yellow.bold
end
# determine if gallery is blank or null, then loop through data.
if "#{id["attributes"]["gallery"]["data"]}".blank? || "#{id["attributes"]["gallery"]["data"]}".empty?
Jekyll.logger.debug "WARNING: the gallery data is missing".to_s.magenta
else
# we only need the urls for each image to prep for download
gallery_images = id["attributes"]["gallery"]["data"]
# loop through each product image.
gallery_images.each do |image|
puts ""
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Gallery image url(s): " "#{image["attributes"]["url"]}".to_s.yellow.bold
end
puts "" # pretty debug spacing
end
# determine if banner_image_description is blank or null.
if "#{id["attributes"]["banner_image_description"]}".blank?
Jekyll.logger.debug "WARNING: the banner_image_description is missing; does post [" "#{title}] have a banner_image_description?".to_s.yellow
else
banner_image_description = id["attributes"]["banner_image_description"]
Jekyll.logger.debug "::DOCUMENT POST DEBUG:: Banner image desc: " "#{banner_image_description}".to_s.yellow
end
# determine if tags data is blank or null, then loop through data.
if "#{id["attributes"]["tags"]["data"]}".blank? || "#{id["attributes"]["tags"]["data"]}".empty?
Jekyll.logger.debug "ERROR: the tags are missing; does post [" "#{title}] have tags?".to_s.red
else
# an array for storing multiple inputs
tags = id["attributes"]["tags"]["data"]
# loop through each post tag.
tags.each do |tag|
puts ""
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Tag(s): " "#{tag["attributes"]["tag"]}".to_s.yellow
end
puts "" # pretty debug spacing
end
# determine if category data is blank or null; only one category per post.
if "#{id["attributes"]["category"]["data"]}".blank? || "#{id["attributes"]["category"]["data"]}".empty?
Jekyll.logger.debug "ERROR: the category is missing; does post [" "#{title}] have a category?".to_s.red
else
category = id["attributes"]["category"]["data"]["attributes"]["name"]
Jekyll.logger.debug "::DOCUMENT POST DEBUG:: Category: " "#{category}".to_s.yellow.bold
end
# determine if post content is blank or null.
if "#{id["attributes"]["content"]}".blank?
Jekyll.logger.debug "ERROR: the the content is missing; does post [" "#{title}] have a descrption?".to_s.red
else
content = id["attributes"]["content"]
Jekyll.logger.debug "::DOCUMENT POST DEBUG:: Raw Content: " "#{content}".to_s.yellow
end
# create the filename
file_name = "#{date}-#{slug}#{file_ending}"
# let us put humpty dumpty back together again!
# create a new collection type post *.md
p = File.open( "#{jekyll_post_path}#{file_name}","w" )
# create document.md content in Jekyll yaml formatting
p.puts "---"
p.puts "updatedAt: #{updatedAt}"
p.puts "layout: #{layout}"
p.puts "title: #{title}"
p.puts "subheading: #{subheading}"
p.puts "slug: #{slug}"
p.puts "date: #{date}"
p.puts "author: #{author}"
p.puts "banner_image: #{banner_image}" # the banner images are downloaded from API in image-filter.rb.
p.puts "banner_image_description: #{banner_image_description}"
p.puts "category: " "#{category}"
# add tags without json formatting in pretty format
p.print "tags: " # pretty debug
# loop & gather tags from one post
if "#{id["attributes"]["tags"]}".blank? || "#{id["attributes"]["tags"]}".empty?
Jekyll.logger.debug "WRITING ERROR: the tags are missing; does post [" "#{title}] have any tags?".to_s.red
else
tags = id["attributes"]["tags"]["data"]
# loop through all tags
tags.each do |tag|
p.print tag["attributes"]["tag"]
p.print ", "
end
p.puts "" # pretty debug spacing
end
p.puts "---" # close .yaml file frontmatter
p.puts "#{content}" # write post content
p.close # close the file; stop writing
end
end

View File

@ -0,0 +1,379 @@
# This software generates mardown formatted products from json data.
# Copyright (C) SharpeTronics, Inc. 2013-2023
# Author(s): Charles Sharpe(@odinzu_me) aka SharpeTronics, Inc.
# License: GPLv3
# Version: 1.3
# This is Free Software released under GPLv3. Any misuse of this software
# will be followed up with GPL enforcement via Software Freedom Law Center:
# https://www.softwarefreedom.org/
# If you incorporate or include any code from SharpeTronics, Inc., your
# code must be licensed as GPLv3 (not GPLv2 or MIT)
# The GPLv3 software license applies to the code directly included in this source distribution.
# See the LICENSE & COPYING file for full information.
# Dependencies downloaded as part of the build process may be covered by other open-source licenses.
# We are open to granting a more permissive (such as MIT or Apache 2.0) license to SharpeTronics, Inc.
# software on a *case-by-case* basis, for an agreed upon price. Please email
# info@sharpetronics.com.
# If you would like to contribute to this code, please follow GPLv3 guidelines.
# as an example, after making changes to the software (Called a Fork) and credit the original copyright holder as the creator with your credit added to theirs.
require 'fileutils' # https://ruby-doc.org/stdlib-2.4.1/libdoc/fileutils/rdoc/FileUtils.html
require 'json' # https://ruby-doc.org/stdlib-3.0.2/libdoc/json/rdoc/JSON.html
require 'yaml' # load Jekyll yaml config
require 'active_support/core_ext/object/blank' # load only the specific extension for .blank? support
require 'date' # https://github.com/ruby/date
module Jekyll
# initialize variables
jekyll_product_path = "collections/_products/"
file_ending = ".md"
# load _config.yml
config_yml = "_config.yml"
f = YAML.load(File.read(config_yml.to_s)) # r - read file
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Is config empty? " "#{config_yml.blank?}".to_s.magenta.bold
# is Stripe turned on in site _config.yml file?
stripe_enabled = f['api']['stripe']['enabled']
Jekyll.logger.debug "ENV DEBUG: Is Stripe enabled? " "#{stripe_enabled}".to_s.yellow.bold
# if Stripe is enabled in _config.yml, then generate products
if "#{stripe_enabled}" === "true"
# set filepath, load the json, then parse through json file
json_product_path = f['api']['collections']['products']['filepath']
# must read data into memory before parsing file
read_products_json = File.read(json_product_path) # read json for all products
# parse through json files
parsed_products_file = JSON.parse(read_products_json.to_s) # returns a hash
# cache / verify and download each product data
product_ids = parsed_products_file["data"]
# loop through each collection id
product_ids.each do |id|
# store json specific data for each product
# determine if stripe_id is blank or null.; this unique identifier is used for Stripe product ids also.
# this allows overwriting Stripe id and syncronizes ids created from CMS API.
if "#{id}".blank?
Jekyll.logger.debug "ERROR: the product id is missing;".to_s.red
else
stripe_id = id["id"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Does the JSON data exist? " "#{stripe_id}".to_s.yellow
end
# determine if heading is blank or null.
if "#{id["attributes"]["heading"]}".blank?
Jekyll.logger.debug "ERROR: the product heading is missing; does product [" "#{heading}] have a heading?".to_s.red
else
heading = id["attributes"]["heading"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Heading: " "#{heading}".to_s.yellow.bold
end
# store slug into object (object is auto generated with Strapi plugin)
slug = id["attributes"]["slug"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Slug: " "#{slug}".to_s.yellow
# determine if subheading is blank or null.
if "#{id["attributes"]["subheading"]}".blank?
Jekyll.logger.debug "ERROR: the subheading is missing; does product [" "#{heading}] have a subheading?".to_s.red
else
subheading = id["attributes"]["subheading"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Subheading: " "#{subheading}".to_s.yellow.bold
end
# determine if date is blank or null.
if "#{id["attributes"]["date"]}".blank?
Jekyll.logger.debug "ERROR: the date is missing; does product [" "#{heading}] have a date?".to_s.red
else
date = id["attributes"]["date"]
# store build times of local products with Stripe metadata
# on update too Stripe, updates the Stripe updatedAt time creating an infinite loop; we must have a static local time for each product that doesn't change on pushing to Stripe API
# NOTE: this time needs to be local product data and doesn't come from Strapi CMS API.
local_cms_time = DateTime.strptime(id['attributes']['updatedAt'], '%Y-%m-%dT%H:%M:%S')
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Date: " "#{date}".to_s.yellow
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Build_Time: " "#{local_cms_time}".to_s.yellow
end
# determine if layout is blank or null.
if "#{id["attributes"]["layout"]}".blank?
Jekyll.logger.debug "ERROR: the layout is missing; does product [" "#{heading}] have a layout?".to_s.red
else
layout = id["attributes"]["layout"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Layout: " "#{layout}".to_s.yellow.bold
end
# determine if author data is blank or null.
if "#{id["attributes"]["author"]["data"]}".blank? || "#{id["attributes"]["author"]["data"]}".empty?
Jekyll.logger.debug "ERROR: the author is missing; does product [" "#{heading}] have a author?".to_s.red
else
author = id["attributes"]["author"]["data"]["attributes"]["name"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Author: " "#{author}".to_s.yellow
end
# determine if banner_image is blank or null.
if "#{id["attributes"]["banner_image"]}".blank?
Jekyll.logger.debug "ERROR: the banner_image url is missing; does product [" "#{heading}] have a banner image url?".to_s.red
else
banner_image = id["attributes"]["banner_image"]["data"]["attributes"]["url"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Banner image: " "#{banner_image}".to_s.yellow.bold
end
# determine if gallery is blank or null, then loop through data.
if "#{id["attributes"]["gallery"]["data"]}".blank? || "#{id["attributes"]["gallery"]["data"]}".empty?
Jekyll.logger.debug "WARNING: the gallery data is missing".to_s.magenta
else
# we only need the urls for each image to prep for download
gallery_images = id["attributes"]["gallery"]["data"]
# loop through each product image.
gallery_images.each do |image|
puts ""
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Gallery image url(s): " "#{image["attributes"]["url"]}".to_s.yellow.bold
end
puts "" # pretty debug spacing
end
# determine if banner_image_description is blank or null.
if "#{id["attributes"]["banner_image_description"]}".blank?
Jekyll.logger.debug "ERROR: the banner_image_description is missing; does product [" "#{heading}] have a banner_image_description?".to_s.red
else
banner_image_description = id["attributes"]["banner_image_description"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Banner image desc: " "#{banner_image_description}".to_s.yellow
end
# determine if tags data is blank or null, then loop through data.
if "#{id["attributes"]["tags"]["data"]}".blank? || "#{id["attributes"]["tags"]["data"]}".empty?
Jekyll.logger.debug "ERROR: the tags is missing; does product [" "#{heading}] have tags?".to_s.red
else
# an array for storing multiple inputs
tags = id["attributes"]["tags"]["data"]
# loop through each product tag.
tags.each do |tag|
puts ""
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Tag(s): " "#{tag["attributes"]["tag"]}".to_s.yellow
end
puts "" # pretty debug spacing
end
# determine if category data is blank or null; only one category per product andor post.
if "#{id["attributes"]["category"]["data"]}".blank? || "#{id["attributes"]["category"]["data"]}".empty?
Jekyll.logger.debug "ERROR: the category is missing; does product [" "#{heading}] have a category?".to_s.red
else
category = id["attributes"]["category"]["data"]["attributes"]["name"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Category: " "#{category}".to_s.yellow.bold
end
# determine if product description is blank or null.
if "#{id["attributes"]["description"]}".blank?
Jekyll.logger.debug "ERROR: the the description is missing; does product [" "#{heading}] have a descrption?".to_s.red
else
description = id["attributes"]["description"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Raw Content: " "#{description}".to_s.yellow
end
# determine if is_featured is blank or null.
if "#{id["attributes"]["is_featured"]}".blank?
Jekyll.logger.debug "ERROR: the is_featured is missing; is product " "#{heading} featured?".to_s.red
else
is_featured = id["attributes"]["is_featured"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: is_featured: " "#{is_featured}".to_s.yellow.bold
end
# determine if is_software is blank or null.
if "#{id["attributes"]["is_software"]}".blank?
Jekyll.logger.debug "ERROR: the is_software is missing; is product " "#{heading} software?".to_s.red
else
is_software = id["attributes"]["is_software"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: is_software: " "#{is_software}".to_s.yellow.bold
end
# determine if is_shippable is blank or null.
if "#{id["attributes"]["is_shippable"]}".blank?
Jekyll.logger.debug "ERROR: the is_shippable is missing; is product " "#{heading} shippable?".to_s.red
else
is_shippable = id["attributes"]["is_shippable"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: is_shippable: " "#{is_shippable}".to_s.yellow.bold
end
# determine if unit_price is blank or null.
if "#{id["attributes"]["unit_price"]}".blank?
Jekyll.logger.debug "ERROR: the amount is missing; does product [" "#{heading}] have a price?".to_s.red
else
unit_price = id["attributes"]["unit_price"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: unit_price: $" "#{unit_price}".to_s.yellow.bold
end
# determine if product quantity is blank or null.
if "#{id["attributes"]["quantity"]}".blank?
Jekyll.logger.debug "ERROR: the quantity is missing; does product [" "#{heading}] have a quantity?".to_s.red
else
quantity = id["attributes"]["quantity"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: quantity: " "#{quantity}".to_s.yellow.bold
end
# determine if product weight is blank or null.
if "#{id["attributes"]["weight"]}".blank?
Jekyll.logger.debug "ERROR: the weight is missing; does product [" "#{heading}] have a weight?".to_s.red
else
weight = id["attributes"]["weight"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: weight: " "#{weight}".to_s.yellow.bold
end
# determine if product package_dimensions is blank or null.
if "#{id["attributes"]["package_dimensions"]}".blank?
Jekyll.logger.debug "ERROR: the package_dimensions is missing; does product [" "#{heading}] have a package_dimensions?".to_s.red
else
package_dimensions = id["attributes"]["package_dimensions"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: package_dimensions: " "#{package_dimensions}".to_s.yellow.bold
end
# determine if product material_type is blank or null.
if "#{id["attributes"]["material_type"]}".blank?
Jekyll.logger.debug "ERROR: the material_type is missing; does product [" "#{heading}] have a material_type?".to_s.red
else
material_type = id["attributes"]["material_type"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: material_type: " "#{material_type}".to_s.yellow.bold
end
# determine if product tax_code is blank or null.
if "#{id["attributes"]["tax_code"]}".blank?
Jekyll.logger.debug "ERROR: the tax_code is missing; does product [" "#{heading}] have a tax_code?".to_s.red
else
tax_code = id["attributes"]["tax_code"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: tax_code: " "#{tax_code}".to_s.yellow.bold
end
# determine if product webpage_url is blank or null.
if "#{id["attributes"]["webpage_url"]}".blank?
Jekyll.logger.debug "ERROR: the webpage_url is missing; does product [" "#{heading}] have a webpage_url?".to_s.red
else
webpage_url = id["attributes"]["webpage_url"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: webpage_url: " "#{webpage_url}".to_s.yellow.bold
end
# determine if product shipping_price is blank or null.
if "#{id["attributes"]["shipping_price"]}".blank?
Jekyll.logger.debug "ERROR: the shipping_price is missing; does product [" "#{heading}] have a shipping_price?".to_s.red
else
shipping_price = id["attributes"]["shipping_price"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: shipping_price: " "#{shipping_price}".to_s.yellow.bold
end
# determine if product currency_type is blank or null.
if "#{id["attributes"]["currency_type"]}".blank?
Jekyll.logger.debug "ERROR: the currency_type is missing; does product [" "#{heading}] have a currency_type?".to_s.red
else
currency_type = id["attributes"]["currency_type"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: currency_type: " "#{material_type}".to_s.yellow.bold
end
# determine if product shipping_rates is blank or null.
if "#{id["attributes"]["shipping_rates"]}".blank?
Jekyll.logger.debug "ERROR: the shipping_rates is missing; does product [" "#{heading}] have shipping_rates?".to_s.red
else
shipping_rates = id["attributes"]["shipping_rates"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: shipping_rates: " "#{shipping_rates}".to_s.yellow.bold
#placeholder for looping through each shipping rate option
end
# determine if product shipping_companies is blank or null.
if "#{id["attributes"]["shipping_companies"]}".blank?
Jekyll.logger.debug "ERROR: the shipping_companies is missing; does product [" "#{heading}] have shipping_companies?".to_s.red
else
shipping_companies = id["attributes"]["shipping_companies"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: shipping_companies: " "#{shipping_companies}".to_s.yellow.bold
#placeholder for looping through each shipping_companies option
end
# determine if product country_origin is blank or null.
if "#{id["attributes"]["country_origin"]}".blank?
Jekyll.logger.debug "ERROR: the country_origin is missing; does product [" "#{heading}] have a country_origin?".to_s.red
else
country_origin = id["attributes"]["country_origin"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: country_origin: " "#{country_origin}".to_s.yellow.bold
end
# create the filename
file_name = "#{date}-#{slug}#{file_ending}"
# let us put humpty dumpty back together again!
# create a new collection type post *.md
p = File.open( "#{jekyll_product_path}#{file_name}","w" )
# create document.md content in Jekyll yaml formatting
p.puts "---"
p.puts "stripe_id: #{stripe_id}"
p.puts "metadata: #{local_cms_time}"
p.puts "layout: #{layout}"
p.puts "heading: #{heading}"
p.puts "subheading: #{subheading}"
p.puts "slug: #{slug}"
p.puts "date: #{date}"
p.puts "author: #{author}"
p.puts "banner_image: #{banner_image}" # the banner images are downloaded from API in image-filter.rb.
p.puts "banner_image_description: #{banner_image_description}"
p.puts "category: " "#{category}"
# add gallery images without json formatting in pretty format
p.print "gallery: \n" # pretty debug
# loop & gather gallery images from one product
if "#{id["attributes"]["gallery"]["data"]}".blank?
Jekyll.logger.debug "WRITING ERROR: the gallery images are missing; does product [" "#{heading}] have any gallery images?".to_s.red
else
gallery = id["attributes"]["gallery"]["data"]
# loop through all tags
gallery.each do |gallery_image|
p.print " - image_path: " "#{gallery_image["attributes"]["url"]} \n"
p.print " title: " "#{gallery_image["attributes"]["hash"]} \n"
end
p.puts "" # pretty debug spacing
end
# add tags without json formatting in pretty format
p.print "tags: " # pretty debug
# loop & gather tags from one product
if "#{id["attributes"]["tags"]["data"]}".blank?
Jekyll.logger.debug "WRITING ERROR: the tags are missing; does product [" "#{heading}] have any tags?".to_s.red
else
tags = id["attributes"]["tags"]["data"]
# loop through all tags
tags.each do |tag|
p.print
p.print tag["attributes"]["tag"]
p.print ", "
end
p.puts "" # pretty debug spacing
end
p.puts "webpage_url: #{webpage_url}"
p.puts "is_featured: #{is_featured}"
p.puts "is_software: #{is_software}"
p.puts "is_shippable: #{is_shippable}"
p.puts "currency_type: #{currency_type}"
p.puts "country_origin: #{country_origin}"
p.puts "unit_price: #{unit_price}"
p.puts "quantity: #{quantity}"
p.puts "package_dimensions: #{package_dimensions}"
p.puts "material_type: #{material_type}"
p.puts "weight: #{weight}"
p.puts "tax_code: #{tax_code}"
p.puts "shipping_price: #{shipping_price}"
p.puts "shipping_rates: #{shipping_rates}"
p.puts "shipping_company: #{shipping_companies}"
p.puts "---" # close .yaml file frontmatter
p.puts "#{description}" # write product description
p.close # close the file; stop writing
end
else
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Stripe is disabled in the _config.yml"
end
end

View File

@ -1,9 +1,9 @@
# This software gathers all collection types from an API and saves that data into Jekyll _data/ folder.
# This software refactors static json image data and downloads unknown images for building a Jekyll web app.
# Copyright (C) SharpeTronics, Inc. 2013-2023
# Author(s): Charles Sharpe(@odinzu_me)
# Author(s): Charles Sharpe(@odinzu_me) aka SharpeTronics, Inc.
# License: GPLv3
# Version: 1
# Version: 1.3
# This is Free Software released under GPLv3. Any misuse of this software
# will be followed up with GPL enforcement via Software Freedom Law Center:
@ -18,8 +18,8 @@
# Dependencies downloaded as part of the build process may be covered by other open-source licenses.
# We are open to granting a more permissive (such as MIT or Apache 2.0) license to SharpeTronics, Inc.
# software on a *case-by-case* basis, for an agreed upon price. Please contact
# info@sharpetronics.com if you are interested.
# software on a *case-by-case* basis, for an agreed upon price. Please email
# info@sharpetronics.com.
# If you would like to contribute to this code, please follow GPLv3 guidelines.
# as an example, after making changes to the software (Called a Fork) and credit the original copyright holder as the creator with your credit added to theirs.
@ -29,6 +29,7 @@ require 'yaml' # load jekyll yaml config
require 'faraday' # https://lostisland.github.io/faraday/usage/
require 'faraday/multipart' # https://github.com/lostisland/faraday-multipart
require 'httpx/adapters/faraday' # https://honeyryderchuck.gitlab.io/httpx/
require 'active_support/core_ext/object/blank' # load only the specific extension for .blank? support
# load and verify _config.yml
config_yml = "_config.yml"
@ -36,97 +37,281 @@ f = YAML.load(File.read(config_yml.to_s)) # r - read file
api_endpoint = f['api']['endpoint']
Jekyll.logger.debug "CONFIG DEBUG: API_ENDPDOINT: " "#{api_endpoint}".to_s.yellow
media_dir = f['api']['local_media_dir']
Jekyll.logger.debug "CONFIG DEBUG: MEDIA DIR: " "#{media_dir}".to_s.yellow.bold
output = f['api']['output']
Jekyll.logger.debug "CONFIG DEBUG: OUTPUT CONFIG: " "#{output}".to_s.yellow
Jekyll.logger.debug "CONFIG DEBUG: MEDIA_DIR: " "#{media_dir}".to_s.yellow.bold
cache_images = f['api']['cache_images']
Jekyll.logger.debug "CONFIG DEBUG: CACHED_IMAGES_DIR: " "#{cache_images}".to_s.yellow
# check if output is true or false in _config.yml
if "#{output}" === "false" || nil
Jekyll.logger.debug "CONFIG DEBUG: CONFIG FAILED TO LOAD".to_s.yellow
# check if cache_images is true or false in _config.yml
if "#{cache_images}" === "false" # "If A described a set, would B be a member of that set?" Jörg W Mittag
Jekyll.logger.debug "CONFIG DEBUG: Downloading images is DISABLED in _config.yml.".to_s.yellow
else
# create image directory if doesn't exist
# determine image directory filepath in _config.yml
if not Dir.exist?(f['api']['local_media_dir'].to_s)
Jekyll.logger.info "the image directory does not exist, I am going to create one".to_s.red
Jekyll.logger.info "the Jekyll image directory does not exist, see _config_yml api --> local_media_dir.".to_s.red
Dir.mkdir f['api']['local_media_dir'].to_s
Jekyll.logger.info "CONFIG DEBUG: The local media directory is created at: #{f['api']['local_media_dir'].to_s}".to_s.yellow
end
# All images are downloaded from EACH NEW collection
# Each collection is parsed through the local _data json
# Furthermore, the url is pieced together on each collection type like a post or product.
# All images are downloaded from EACH NEW collection
# Each collection is parsed through the local _data json
# Furthermore, the url is pieced together on each collection type like a post or product.
# prepare http api connection
api_builder = Faraday.new do |builder|
# add by symbol, lookup from Faraday::Request,
# Faraday::Response and Faraday::Adapter registries
builder.adapter :httpx # must add adapter; default is Net:HTTP
#builder.request :authorization, options
builder.request :multipart
# identical, but add the class directly instead of using lookups
builder.use Faraday::Response::RaiseError
end
Jekyll.logger.debug "HTTP DEBUG: BULIDING CONNECTION: #{api_builder}".to_s.yellow
# prepare http api connection; this is used for each collection type
api_builder = Faraday.new do |builder|
# add by symbol, lookup from Faraday::Request,
# Faraday::Response and Faraday::Adapter registries
builder.adapter :httpx # must add adapter; default is Net:HTTP
#builder.request :authorization, options
builder.request :multipart
# identical, but add the class directly instead of using lookups
builder.use Faraday::Response::RaiseError
end # api_builder
Jekyll.logger.debug "HTTP DEBUG: BULIDING CONNECTION: #{api_builder}".to_s.yellow
# load file, then parse through json file in _data/posts/index.json
# add new collections here
json_post_path = f['api']['collections']['posts']['filepath']
Jekyll.logger.debug "JSON DEBUG: GET JSON CONFIG PATH: " "#{json_post_path}".to_s.yellow.bold
# TODO: add product_path to parsed_json_file
#json_product_path = f['api']['collections']['products']['path']
#Jekyll.logger.debug "DEBUG: OUTPUT CONFIG: " "#{json_product_path}".to_s.yellow
# begin sorting through PRODUCT json data
# determine if using ecommerce integration, then prepare product images from sorting the json data.
if f['api']['collections']['products']['type'] != 'products' # case sensitive
Jekyll.logger.debug "CONFIG DEBUG: PRODUCTS FILEPATH IS MISSING IN JEKYLL _CONFIG.YML ".to_s.red.bold
else
# load filepath, then parse through json file in _data/posts/index.json
json_product_path = f['api']['collections']['products']['filepath']
Jekyll.logger.debug "CONFIG DEBUG: PRODUCTS PATH: " "#{json_product_path}".to_s.yellow.bold
# TODO: add extra error log if file is missing
read_json = File.read(json_post_path) # read json for all posts
#Jekyll.logger.debug "DEBUG: READ JSON FILE: " "#{read_json}".to_s.yellow.bold # basic debug test
read_product_json = File.read(json_product_path) # read json for all posts
#Jekyll.logger.debug "DEBUG: READ JSON FILE: " "#{read_product_json}".to_s.yellow.bold # basic debug test
parsed_json_file = JSON.parse(read_json.to_s) # returns json hash
Jekyll.logger.debug "JSON DEBUG: IS parsed_json_file EMPTY? " "#{parsed_json_file.empty?}".to_s.yellow # basic debug test
parsed_product_json_file = JSON.parse(read_product_json.to_s) # returns json hash
Jekyll.logger.debug "JSON DEBUG: IS PARSED_JSON_FILE MISSING? " "#{parsed_product_json_file.blank?}".to_s.magenta # basic debug test
# cache / check and download all collection image data
collection_ids = parsed_json_file["data"]
# loop through each collection id
collection_ids.each do |id|
#puts "#{id}".yellow # output collection id for debug
# cache / check and download all PRODUCT image data
product_collection_ids = parsed_product_json_file["data"]
# loop through each product collection id
product_collection_ids.each do |id|
# get image_url
if "#{id["attributes"]["image"]}".to_s.empty? || nil || "#{id["attributes"]["image"]["data"]}".to_s.empty?
Jekyll.logger.debug "ERROR: IMAGE DATA EMPTY for COLLECTION: " "#{id["attributes"]["title"]}".to_s.red # basic debug test
else
# set uri_path
uri_path = "#{api_endpoint}""#{id["attributes"]["image"]["data"]["attributes"]["url"]}"
Jekyll.logger.debug "HTTP DEBUG: URI_PATH:" "#{uri_path}".to_s.yellow.bold
# get file_name
file_name = "#{id["attributes"]["image"]["data"]["attributes"]["hash"]}"
# prepare file
file_ext = File.extname(uri_path) # get file extension from API
Jekyll.logger.debug "FILE DEBUG: THE FILE EXTENSION NAME " "#{file_ext}".to_s.yellow.bold # basic debug test
# TODO: add image modified time to each API image
#puts File.exist?(media_dir + file_name + file_ext) #debug if File exists
if File.exist?(media_dir + file_name + file_ext) === false
# where the magic happens; download a new image
image = api_builder.get(uri_path)
Jekyll.logger.debug "DOWNLOADING... IMAGE URL IS: " "#{id["attributes"]["image"]["data"]["attributes"]["url"]}".to_s.green # basic debug test
Jekyll.logger.debug "HTTP DEBUG: A NEW IMAGE HTTP(S) RESPONSE: " "#{image.status}\n" "#{image.headers}\n".to_s.yellow # debug http response status
# only save file if data exists
file_exist = File.exist?(media_dir + file_name + file_ext) # file already exists? then, TODO: skip
Jekyll.logger.debug "FILE DEBUG: DOES FILE ALREADY EXIST? " "#{file_exist}".to_s.yellow # basic debug test
# TODO: enable to work with Windows NTFS File Systems
#file_ctime = File.ctime(media_dir + file_name + file_ext) # in NTFS (Windows) returns creation time (birthtime)
#Jekyll.logger.debug "DEBUG: WHEN WAS FILE LAST MODIFIED? " "#{file_ctime}".to_s.yellow # basic debug test
c = File.open(file_name + file_ext, 'w') # w - Create an empty file for writing.
c.write(image.body)
c.close
FileUtils.mv "#{c.path}", "#{media_dir}"
Jekyll.logger.debug "FILE DEBUG: THE WHOLE FILE NAME " "#{file_name}" "#{file_ext}".to_s.yellow.bold # basic debug test
# loop through gallery image data if exists
if "#{id["attributes"]["gallery"]["data"]}".blank? || "#{id["attributes"]["gallery"]["data"]}".empty?
Jekyll.logger.debug "GALLERY DEBUG: THE PRODUCT GALLERY DATA DOESN'T EXIST "
else
Jekyll.logger.debug "WARNING: FILE ALREADY EXISTS - SKIPPING".to_s.red.bold # basic debug test
end
end # end if output = true
end
end
# we only need the urls for each image to prep for download
product_gallery_images = id["attributes"]["gallery"]["data"]
# loop through each product image.
product_gallery_images.each do |image|
# prepare gallery_image_uri_path and store in a variable https://www.example.com/uploads/example.webp
product_gallery_image_uri_path = "#{api_endpoint}""#{image["attributes"]["url"]}"
Jekyll.logger.debug "PRODUCT FILE DEBUG: GALLERY IMAGE PATH: " "#{product_gallery_image_uri_path}".to_s.yellow
# prepare gallery_image_file_name and store in a variable
product_gallery_image_file_name = "#{image["attributes"]["hash"]}"
Jekyll.logger.debug "PRODUCT FILE DEBUG: GALLERY IMAGE FILE NAME: " "#{product_gallery_image_file_name}".to_s.yellow.bold
# prepare gallery_image_file_ext and store in a variable
product_gallery_image_file_ext = "#{image["attributes"]["ext"]}" # get file extension from API
Jekyll.logger.debug "PRODUCT FILE DEBUG: GALLERY IMAGE FILE EXT: " "#{product_gallery_image_file_ext}".to_s.yellow
puts ""
# if cached PRODUCT product_gallery_images exist, skip; else check modified time.
#File.exist?(media_dir + product_gallery_image_file_name + product_gallery_image_file_ext)
if File.exist?(media_dir + product_gallery_image_file_name + product_gallery_image_file_ext) === false
# where the magic happens; we finally download a new image
gallery_download_image = api_builder.get(product_gallery_image_uri_path)
Jekyll.logger.debug "DOWNLOADING... THE GALLERY PRODUCT IMAGE URI IS: " "#{product_gallery_image_uri_path}".to_s.cyan.bold # basic debug test
Jekyll.logger.debug "HTTP DEBUG: A NEW GALLERY PRODUCT IMAGE HTTP(S) RESPONSE: " "#{gallery_download_image.status}\n" "#{gallery_download_image.headers}\n".to_s.yellow # debug http response status
# only save file if data exists
file_exist_debug = File.exist?(media_dir + product_gallery_image_file_name + product_gallery_image_file_ext) # file already exists? then, TODO: skip
Jekyll.logger.debug "FILE DEBUG: DOES GALLERY PRODUCT IMAGE ALREADY EXIST? " "#{file_exist_debug}".to_s.yellow # basic debug test
# TODO: enable to work with Windows NTFS File Systems
#file_ctime = File.ctime(media_dir + file_name + file_ext) # in NTFS (Windows) returns creation time (birthtime)
#Jekyll.logger.debug "DEBUG: WHEN WAS FILE LAST MODIFIED? " "#{file_ctime}".to_s.yellow # basic debug test
c = File.open(product_gallery_image_file_name + product_gallery_image_file_ext, 'w') # w - Create an empty file for writing.
c.write(gallery_download_image.body) # write the download to local media_dir
c.close # close the file
FileUtils.mv "#{c.path}", "#{media_dir}" # move the file to custom path
Jekyll.logger.debug "FILE DEBUG: THE WHOLE GALLERY PRODUCT IMAGE FILE NAME " "#{product_gallery_image_file_name}" "#{product_gallery_image_file_ext}".to_s.yellow.bold # basic debug test
else
Jekyll.logger.debug "PRODUCT GALLERY IMAGE ALREADY EXISTS - SKIPPING".to_s.magenta
# get banner_image_uri_path from each PRODUCT
if "#{id["attributes"]["banner_image"]["data"]}".blank? || "#{id["attributes"]["banner_image"]["data"]}".empty?
Jekyll.logger.debug "ERROR: IMAGE DATA EMPTY for PRODUCT: " "#{id["attributes"]["name"]}".to_s.red # basic debug test
else
# set uri_path https://www.example.com/uploads/example.webp
banner_image_uri_path = "#{api_endpoint}""#{id["attributes"]["banner_image"]["data"]["attributes"]["url"]}"
Jekyll.logger.debug "PRODUCT FILE DEBUG: PRODUCT BANNER_IMAGE URI_PATH: " "#{banner_image_uri_path}".to_s.yellow
# get image_file_name
banner_image_file_name = "#{id["attributes"]["banner_image"]["data"]["attributes"]["hash"]}"
Jekyll.logger.debug "PRODUCT FILE DEBUG: PRODUCT BANNER_IMAGE URI_PATH: " "#{banner_image_file_name}".to_s.yellow.bold
# prepare filename
banner_image_file_ext = "#{id["attributes"]["banner_image"]["data"]["attributes"]["ext"]}"
Jekyll.logger.debug "PRODUCT FILE DEBUG: THE FILE EXTENSION NAME: " "#{banner_image_file_ext}".to_s.yellow # basic debug test
# if cached PRODUCT banner_image_file_name exists, skip; else check modified time.
#File.exist?(media_dir + banner_image_file_name + banner_image_file_ext).to_s.yellow.bold
File.exist?(media_dir + banner_image_file_name + banner_image_file_ext)
if File.exist?(media_dir + banner_image_file_name + banner_image_file_ext) == false
# where the magic happens; we finally download a new image
download_image = api_builder.get(banner_image_uri_path)
Jekyll.logger.debug "DOWNLOADING... THE PRODUCT IMAGE URI IS: " "#{banner_image_uri_path}".to_s.cyan.bold # basic debug test
Jekyll.logger.debug "HTTP DEBUG: A NEW PRODUCT IMAGE HTTP(S) RESPONSE: " "#{download_image.status}\n" "#{download_image.headers}\n".to_s.yellow # debug http response status
# only save file if data exists
file_exist_debug = File.exist?(media_dir + banner_image_file_name + banner_image_file_ext) # file already exists? then, TODO: skip
Jekyll.logger.debug "FILE DEBUG: DOES PRODUCT IMAGE ALREADY EXIST? " "#{file_exist_debug}".to_s.yellow # basic debug test
# TODO: enable to work with Windows NTFS File Systems
#file_ctime = File.ctime(media_dir + file_name + file_ext) # in NTFS (Windows) returns creation time (birthtime)
#Jekyll.logger.debug "DEBUG: WHEN WAS FILE LAST MODIFIED? " "#{file_ctime}".to_s.yellow # basic debug test
c = File.open(banner_image_file_name + banner_image_file_ext, 'w') # w - Create an empty file for writing.
c.write(download_image.body) # write the download to local media_dir
c.close # close the file
FileUtils.mv "#{c.path}", "#{media_dir}" # move the file to custom path
Jekyll.logger.debug "FILE DEBUG: THE WHOLE PRODUCT BANNER IMAGE FILE NAME " "#{banner_image_file_name}" "#{banner_image_file_ext}".to_s.yellow.bold # basic debug test
else
Jekyll.logger.debug "PRODUCT BANNER IMAGE ALREADY EXISTS - SKIPPING".to_s.magenta
end
end # end banner_image data
end # end cached if file exists
end # ends product gallery images each loop
puts "" # pretty debug spacing
end # ends product gallery image data loop
end # end product_collection_ids
puts "" # pretty debug spacing
end # end product formatting check
# begin parsing through POST json data.
# prepare post images from sorting the json data.
if f['api']['collections']['posts']['type'] != 'posts' # case sensitive
Jekyll.logger.debug "CONFIG DEBUG: POSTS FILEPATH IS MISSING IN JEKYLL _CONFIG.YML ".to_s.red
else
# load filepath, then parse through json file in _data/posts/index.json
json_post_path = f['api']['collections']['posts']['filepath']
Jekyll.logger.debug "CONFIG DEBUG: POSTS PATH: " "#{json_post_path}".to_s.yellow.bold
read_post_json = File.read(json_post_path) # read json for all posts
#Jekyll.logger.debug "DEBUG: READ JSON FILE: " "#{read_post_json}".to_s.yellow.bold # basic debug test
parsed_post_json_file = JSON.parse(read_post_json.to_s) # returns json hash
Jekyll.logger.debug "JSON DEBUG: IS PARSED_JSON_FILE MISSING? " "#{parsed_post_json_file.blank?}".to_s.yellow # basic debug test
# cache / check and download all POSTS image data
post_collection_ids = parsed_post_json_file["data"]
# loop through each post collection id
post_collection_ids.each do |id|
# loop through post gallery image data if exists
if "#{id["attributes"]["gallery"]["data"]}".blank? || "#{id["attributes"]["gallery"]["data"]}".empty?
Jekyll.logger.debug "GALLERY DEBUG: THE POST ID: " "#{id["id"]} " "GALLERY DATA DOESN'T EXIST".to_s.magenta
else
# we only need the urls for each image to prep for download
post_gallery_images = id["attributes"]["gallery"]["data"]
# loop through each post image.
post_gallery_images.each do |post_image|
# prepare gallery_image_uri_path and store in a variable https://www.example.com/uploads/example.webp
post_gallery_image_uri_path = "#{api_endpoint}""#{post_image["attributes"]["url"]}"
Jekyll.logger.debug "POST FILE DEBUG: POST gallery_image_uri_path: " "#{post_gallery_image_uri_path}".to_s.yellow
# prepare gallery_image_file_name and store in a variable
post_gallery_image_file_name = "#{post_image["attributes"]["hash"]}"
Jekyll.logger.debug "POST FILE DEBUG: POST gallery_image_file_name: " "#{post_gallery_image_file_name}".to_s.yellow.bold
# prepare gallery_image_file_ext and store in a variable
post_gallery_image_file_ext = "#{post_image["attributes"]["ext"]}" # get file extension from API
Jekyll.logger.debug "POST FILE DEBUG: THE POST gallery_image_file_ext: " "#{post_gallery_image_file_ext}".to_s.yellow # basic debug test
puts ""
# if cached POST post_banner_image_file_name exists, skip; else check modified time.
if File.exist?(media_dir + post_gallery_image_file_name + post_gallery_image_file_ext) === false
# where the magic happens; we finally download a new image
post_gallery_download_image = api_builder.get(post_gallery_image_uri_path)
Jekyll.logger.debug "DOWNLOADING... THE GALLERY POST IMAGE URI IS: " "#{post_gallery_image_uri_path}".to_s.cyan.bold # basic debug test
Jekyll.logger.debug "HTTP DEBUG: A NEW GALLERY POST IMAGE HTTP(S) RESPONSE: " "#{post_gallery_download_image.status}\n" "#{post_gallery_download_image.headers}\n".to_s.yellow # debug http response status
# only save file if data exists
post_gallery_file_exist_debug = File.exist?(media_dir + post_gallery_image_file_name + post_gallery_image_file_ext) # file already exists? then, TODO: skip
Jekyll.logger.debug "FILE DEBUG: DOES GALLERY POST IMAGE ALREADY EXIST? " "#{post_gallery_file_exist_debug}".to_s.yellow # basic debug test
# TODO: enable to work with Windows NTFS File Systems
#file_ctime = File.ctime(media_dir + file_name + file_ext) # in NTFS (Windows) returns creation time (birthtime)
#Jekyll.logger.debug "DEBUG: WHEN WAS FILE LAST MODIFIED? " "#{file_ctime}".to_s.yellow # basic debug test
c = File.open(post_gallery_image_file_name + post_gallery_image_file_ext, 'w') # w - Create an empty file for writing.
c.write(post_gallery_download_image.body) # write the download to local media_dir
c.close # close the file
FileUtils.mv "#{c.path}", "#{media_dir}" # move the file to custom path
Jekyll.logger.debug "FILE DEBUG: THE WHOLE GALLERY POST IMAGE FILE NAME " "#{post_gallery_image_file_name}" "#{post_gallery_image_file_ext}".to_s.yellow.bold # basic debug test
else
Jekyll.logger.debug "POST GALLERY IMAGE ALREADY EXISTS - SKIPPING".to_s.magenta
end # ends does post gallery image exist?
end # end post_gallery_images each loop
puts "" # pretty debug spacing
end # ends post gallery image data loop
# we only need the urls for each image to prep for download
#pp id
post_banner_images = id["attributes"]["banner_image"]["data"]
# loop through each post image.
post_banner_images.each do |banner_image|
# get post_banner_image_uri_path from each POST
if banner_image.blank? || banner_image.empty?
Jekyll.logger.debug "ERROR: IMAGE DATA EMPTY for POST: " "#{banner_image["attributes"]["name"]}".to_s.red # basic debug test
else
# set uri_path https://www.example.com/uploads/example.webp
post_banner_image_uri_path = "#{api_endpoint}#{id["attributes"]["banner_image"]["data"]["attributes"]["url"]}"
Jekyll.logger.debug "POST FILE DEBUG: POST BANNER_IMAGE URI_PATH: " "#{post_banner_image_uri_path}".to_s.yellow.bold
# get image_file_name
post_banner_image_file_name = "#{id["attributes"]["banner_image"]["data"]["attributes"]["hash"]}"
Jekyll.logger.debug "POST FILE DEBUG: POST BANNER_IMAGE URI_PATH: " "#{post_banner_image_file_name}".to_s.yellow.bold
# prepare filename
post_banner_image_file_ext = "#{id["attributes"]["banner_image"]["data"]["attributes"]["ext"]}"
Jekyll.logger.debug "POST FILE DEBUG: THE FILE EXTENSION NAME: " "#{post_banner_image_file_ext}".to_s.yellow.bold # basic debug test
# if cached POST post_banner_image_file_name exists, skip; else check modified time.
if File.exist?(media_dir + post_banner_image_file_name + post_banner_image_file_ext) === false
# where the magic happens; we finally download a new image
post_banner_download_image = api_builder.get(post_banner_image_uri_path)
Jekyll.logger.debug "DOWNLOADING... THE POST BANNER IMAGE URI IS: " "#{post_banner_image_uri_path}".to_s.cyan.bold # basic debug test
Jekyll.logger.debug "HTTP DEBUG: A NEW POST BANNER IMAGE HTTP(S) RESPONSE: " "#{post_banner_download_image.status}\n" "#{post_banner_download_image.headers}\n".to_s.yellow # debug http response status
# only save file if data exists
post_banner_file_exist_debug = File.exist?(media_dir + post_banner_image_file_name + post_banner_image_file_ext) # file already exists?
Jekyll.logger.debug "FILE DEBUG: DOES POST BANNER IMAGE ALREADY EXIST? " "#{post_banner_file_exist_debug}".to_s.yellow # basic debug test
# TODO: enable to work with Windows NTFS File Systems
#file_ctime = File.ctime(media_dir + file_name + file_ext) # in NTFS (Windows) returns creation time (birthtime)
#Jekyll.logger.debug "DEBUG: WHEN WAS FILE LAST MODIFIED? " "#{file_ctime}".to_s.yellow # basic debug test
c = File.open(post_banner_image_file_name + post_banner_image_file_ext, 'w') # w - Create an empty file for writing.
c.write(post_banner_download_image.body) # write the download to local media_dir
c.close # close the file
FileUtils.mv "#{c.path}", "#{media_dir}" # move the file to custom path
Jekyll.logger.debug "FILE DEBUG: THE WHOLE POST BANNER IMAGE FILE NAME " "#{post_banner_image_file_name}" "#{post_banner_image_file_ext}".to_s.yellow.bold # basic debug test
else
Jekyll.logger.debug "POST BANNER IMAGE ALREADY EXISTS - SKIPPING".to_s.magenta
end # end cached if file exists
end # post banner data exist?
end # post_banner_images.each do
end # ends post collection id exist?
puts "" # pretty debug spacing
end # end post formatting check
end # end is cache_images enabled?

View File

@ -0,0 +1,373 @@
# This software creates product data from the Stripe API and populates it on Strapi frontend dashboard.
# Copyright (C) SharpeTronics, Inc. 2013-2023
# Author(s): Charles Sharpe(@odinzu_me) aka SharpeTronics, Inc.
# License: GPLv3
# Version: 1.3
# This is Free Software released under GPLv3. Any misuse of this software
# will be followed up with GPL enforcement via Software Freedom Law Center:
# https://www.softwarefreedom.org/
# If you incorporate or include any code from SharpeTronics, Inc., your
# code must be licensed as GPLv3 (not GPLv2 or MIT)
# The GPLv3 software license applies to the code directly included in this source distribution.
# See the LICENSE & COPYING file for full information.
# Dependencies downloaded as part of the build process may be covered by other open-source licenses.
# We are open to granting a more permissive (such as MIT or Apache 2.0) license to SharpeTronics, Inc.
# software on a *case-by-case* basis, for an agreed upon price. Please email
# info@sharpetronics.com.
# If you would like to contribute to this code, please follow GPLv3 guidelines.
# as an example, after making changes to the software (Called a Fork) and credit the original copyright holder as the creator with your credit added to theirs.
require 'fileutils' # https://ruby-doc.org/stdlib-2.4.1/libdoc/fileutils/rdoc/FileUtils.html
require 'yaml' # https://github.com/ruby/yaml
require 'faraday' # https://lostisland.github.io/faraday/usage/
require 'faraday/multipart' # https://github.com/lostisland/faraday-multipart
require 'httpx/adapters/faraday' # https://honeyryderchuck.gitlab.io/httpx/
require 'stripe' # https://github.com/stripe/stripe-ruby
require 'active_support/core_ext/object/blank' # load only the specific extension for .blank? support; normally used with Rails; see Jekyll gemfile
require 'date' # https://github.com/ruby/date
require 'json' # https://ruby-doc.org/stdlib-3.0.2/libdoc/json/rdoc/JSON.html
# read local Jekyll _config.yml data into memory
config_yml = "_config.yml"
f = YAML.load(File.read(config_yml.to_s)) # r - read file
# is Stripe turned on in site _config.yml file?
stripe_enabled = f['api']['stripe']['enabled']
# is Stripe turned on in site _config.yml file?
site_endpoint = f['api']['endpoint']
# reset the Stripe products db
stripe_db_reset = f['api']['stripe']['reset_stripe_db']
Jekyll.logger.debug "ENV DEBUG: Is Stripe enabled? " "#{stripe_enabled}".to_s.yellow.bold
# if Stripe is enabled in _config.yml, get tokens from local environment for accessing Stripe API [see documentation]
if "#{stripe_enabled}" === "true"
remote_stripe_name = nil # initialize the variable outside the loop
local_stripe_name = nil # initialize the variable outside the loop
# set api key globally with Stripe gem
Stripe.api_key = ENV['STRIPE_LIVE_KEY'] # retrieved from docker-compose machine
Stripe.max_network_retries = 3
Stripe.open_timeout = 30 # in seconds
# store remote stripe json data from Stripe products
remote_stripe_json_products = Stripe::Product.list # user must create product on Stripe (Live Key)
# retrieve remote Stripe product name if exists
# parse through json file
remote_parse_products = JSON.parse(remote_stripe_json_products.to_s) # returns a hash
Jekyll.logger.debug "STRIPE HTTPS DEBUG: Download all remote products: \n\n" "#{remote_parse_products} \n".to_s.cyan.bold
# cache, verify and download each product data from product_name
remote_stripe_product_data = remote_parse_products["data"].sort_by { |v| -v['id'] } # need ids in ascending order
# remove all default Stripe data ids that begin with prod_ (ids created with Stripe dashboard))
filtered_cached_remote_data = remote_stripe_product_data.delete_if{|v| v['id'] =~ /^prod_/} # deletes id hash if exists
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Filtered Cached Remote Product IDs: \n\n" "#{filtered_cached_remote_data}\n".to_s.yellow.bold
# retrieve LOCAL Stripe product name
# set filepath, load the json, then parse through json file
json_product_path = f['api']['collections']['products']['filepath']
# must read data into memory before parsing file
read_products_json = File.read(json_product_path)
# parse through json files
local_parsed_products_file = JSON.parse(read_products_json) # returns a hash
#Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Developer debug: #{local_parsed_products_file}".to_s.yellow
local_product_data = local_parsed_products_file["data"].sort_by { |v| v['id'] } # need ids in ascending order
# must have an array of ids to match against locally; checking against a remote API locally, rather than pinging another server with duplicate data on each build.
cached_local_ids = local_product_data.map { |i| i["id"] }
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Cached Local Product ID: " "#{cached_local_ids}".to_s.yellow.bold
cached_remote_ids = remote_stripe_product_data.map { |x| x["id"]} # cache all remote Stripe data.
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Cached Remote Product IDs: " "#{cached_remote_ids}".to_s.yellow.bold
cached_remote_updated_product_time = remote_stripe_product_data.map { |x| x["updated"]}
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Cached Remote Product Modify Times: " "#{cached_remote_updated_product_time}".to_s.yellow.bold
# begin psueodo code here, b3ep b(oo)p b0p!
if filtered_cached_remote_data.present?
# the following loop only 'counts' each remote product ID from Stripe API
filtered_cached_remote_data.each do |update_product|
# conv remote Stripe product unix epoch time into proper format before local_product loop
remote_conv_modify_time = update_product['metadata'].dig('build_time')
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Remote Product ID: " "#{update_product['id']}" " updated at: " "#{remote_conv_modify_time} \n".to_s.yellow.bold
# next, we loop through all local product data
# Go through each local product , then MEASURE against REMOTE TIME product after converted to same format
local_product_data.each do |local_product|
# store local modify time; all time from Strapi API should be the same
# this field is currently able to change in Strapi CMS dashboard
local_conv_modify_time = DateTime.strptime(local_product['attributes']['updatedAt'], '%Y-%m-%dT%H:%M:%S')
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Product ID: " "#{local_product['id']}" " updated at: " "#{local_conv_modify_time} \n".to_s.yellow.bold
# if ids equal, deteremine if modify time is different
if local_product['id'].to_s == update_product['id'].to_s # going through all local product data and rejecting all product IDs that are EQUAL to update_product; if no matched ids exist, then this loop ends
Jekyll.logger.debug "Product ID MATCH FOUND, comparing modify times... \n".to_s.magenta.bold
# do comparison operation of remote and local modify times.
if local_conv_modify_time.to_s != remote_conv_modify_time.to_s
begin
puts "After checking if remote json data exists, update the product ".to_s.yellow
local_product_name = local_product["attributes"]["heading"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Name: " "#{local_product_name}"
local_product_id = local_product["id"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product ID: " "#{local_product_id}"
# TODO: Quantity needs to be split into a min, max and starting unit amount; also need to custom_unit_amount
#local_product_quantity = local_product["attributes"]["quantity"]
#Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Quantity: " "#{local_product_quantity}"
local_product_description = local_product["attributes"]["description"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Description: " "#{local_product_description}"
local_product_weight = local_product["attributes"]["weight"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Weight: " "#{local_product_weight}"
local_product_webpage_url = local_product["attributes"]["webpage_url"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product WebPage: " "#{local_product_webpage_url}"
local_product_tax_code = local_product["attributes"]["tax_code"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Tax Code: " "#{local_product_tax_code}"
local_product_is_shippable = local_product["attributes"]["is_shippable"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Is Shippable?: " "#{local_product_is_shippable}"
local_product_shipping_rates = local_product["attributes"]["shipping_rates"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Shipping Rates: " "#{local_product_shipping_rates}"
# TODO: On CMS API, we need to split into 4 seperate values; height, length, weight, width with 2 decimal places
#local_product_package_dimensions = local_product["attributes"]["package_dimensions"]
#Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Pk Dimensions: " "#{local_product_package_dimensions}"
local_product_shipping_companies = local_product["attributes"]["shipping_companies"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Shipping Company: " "#{local_product_shipping_companies}"
# Prices defined in each available currency option. Each key must be a three-letter ISO currency code and a supported currency. For example, to define your price in eur, pass the fields below in the eur key of currency_options.
local_product_currency_type = local_product["attributes"]["currency_type"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Currency Type: " "#{local_product_currency_type}"
local_product_shipping_price = local_product["attributes"]["shipping_price"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Shipping Price: " "#{local_product_shipping_price}"
# Same as unit_amount, but accepts a decimal value in cents with at most 12 decimal places. Only one of unit_amount and unit_amount_decimal can be set.
local_product_unit_price = local_product["attributes"]["unit_price"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Unit Price: " "#{local_product_unit_price}"
# TODO
# A label that represents units of this product in Stripe and on customers receipts and invoices. When set, this will be included in associated invoice line item descriptions.
#local_product_unit_label = local_product["attributes"]["unit_label"]
#Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Currency Type: " "#{local_product_unit_label}"
# TODO
# An arbitrary string to be displayed on your customers credit card or bank statement. While most banks display this information consistently, some may display it incorrectly or not at all.
# This may be up to 22 characters. The statement description may not include <, >, \, ", characters, and will appear on your customers statement in capital letters. Non-ASCII characters are automatically stripped. It must contain at least one letter.
#local_product_statement_descriptor = local_product["attributes"]["statement_descriptor"]
#Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Statement Descriptor: " "#{local_product_statement_descriptor}"
# TODO
# Only 8 image URLs per product; loop through each image to get the url
#local_product_images = local_product["attributes"]["gallery"]["data"]["attributes"]["url"]
#Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Gallery Images: " "#{local_product_images}"
local_product_banner_image = local_product["attributes"]["banner_image"]["data"]["attributes"]["url"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Image: " "#{site_endpoint}#{local_product_banner_image}"
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Product Beginning Update " "#{local_product_name}".to_s.yellow.bold
# updates the specific product by setting the values of the parameters passed. Any parameters not provided will be left unchanged.
Stripe::Product.update(
"#{local_product_id}", # prod_id that is being updated
name: "#{local_product_name}",
description: "#{local_product_description}",
metadata: {build_time: "#{local_conv_modify_time}"},
#unit_amount_decimal: "#{local_product_unit_price * 100 }", # format must be in cents e.g. 2000 cents = $20
url: "#{site_endpoint + local_product_webpage_url}",
tax_code: "#{local_product_tax_code}", # must match these codes https://stripe.com/docs/tax/tax-categories
shippable: "#{local_product_is_shippable}",
images: ["#{site_endpoint + local_product_banner_image}"],
# package_dimensions {
# weight: "#{local_product_weight}",
# height: "#{local_product_height}",
# length: "#{local_product_length}",
# width: "#{local_product_width}",
# }
#name: "#{local_product_shipping_rates}",
#name: "#{local_product_shipping_companies}",
#name: "#{local_product_shipping_price}"},
#unit_amount_decimal: "#{local_product_unit_price}",
)
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Product UPDATED! " "#{local_product_name} \n".to_s.cyan.bold
# check relative stripe product id from each new local_product if error arises
Stripe::Product.retrieve(local_product_id.to_s)
rescue Stripe::InvalidRequestError => e
# Invalid parameters were supplied to Stripe's API
Jekyll.logger.debug "Stripe Error: Invalid API Request - SKIPPING PRODUCT: " "#{local_product_name}".to_s.red
end # begin
else
# Skip
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: MODIFY TIMES MATCH, SKIPPING: ".to_s.magenta.bold
end
else
# Skip
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: IDS DON'T MATCH, SKIPPING: ".to_s.magenta.bold
end # remote_product['id'] conditional
end # local product data loop
end # filtered_cached_remote_data
else
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Remote Stripe Data is EMPTY, SKIPPING PRODUCT UPDATES! ".to_s.red.bold
end # filtered_cached_remote_data.present?
if local_product_data.present?
# the following loop only 'counts' each remote product ID from Stripe API
filtered_cached_remote_data.each do |update_product|
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Remote Product ID: " "#{update_product['id']}".to_s.yellow.bold
if filtered_cached_remote_data.present?
local_product_data.each do |local_product|
# if ids are on stripe remote, SKIP
if local_product_data.reject { |i| i["id"] == update_product['id'] } # going through all local product data and rejecting all product IDs that are NOT EQUAL to update_product; if no matched ids exist, then this loop ends
Jekyll.logger.debug "Product ID MATCH FOUND!, SKIPPING \n".to_s.magenta.bold
else
# only execute this after all data is sorted through and compared
# get all product data from each id
begin
puts "Creating products after checking if remote json data exists".to_s.yellow
local_product_name = local_product["attributes"]["heading"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Name: " "#{local_product_name}"
local_product_id = local_product["id"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product ID: " "#{local_product_id}"
# TODO: Quantity needs to be split into a min, max and starting unit amount; also need to custom_unit_amount
#local_product_quantity = local_product["attributes"]["quantity"]
#Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Quantity: " "#{local_product_quantity}"
# store local modify time; all time from Strapi API should be the same
# this field is currently able to change in Strapi CMS dashboard
local_conv_modify_time = DateTime.strptime(local_product['attributes']['updatedAt'], '%Y-%m-%dT%H:%M:%S')
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Product ID: " "#{local_product['id']}" " updated at: " "#{local_conv_modify_time} \n".to_s.yellow.bold
local_product_description = local_product["attributes"]["description"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Description: " "#{local_product_description}"
local_product_weight = local_product["attributes"]["weight"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Weight: " "#{local_product_weight}"
local_product_webpage_url = local_product["attributes"]["webpage_url"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product WebPage: " "#{local_product_webpage_url}"
local_product_tax_code = local_product["attributes"]["tax_code"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Tax Code: " "#{local_product_tax_code}"
local_product_is_shippable = local_product["attributes"]["is_shippable"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Is Shippable?: " "#{local_product_is_shippable}"
local_product_shipping_rates = local_product["attributes"]["shipping_rates"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Shipping Rates: " "#{local_product_shipping_rates}"
# TODO: On CMS API, we need to split into 4 seperate values; height, length, weight, width with 2 decimal places
#local_product_package_dimensions = local_product["attributes"]["package_dimensions"]
#Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Pk Dimensions: " "#{local_product_package_dimensions}"
local_product_shipping_companies = local_product["attributes"]["shipping_companies"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Shipping Company: " "#{local_product_shipping_companies}"
# Prices defined in each available currency option. Each key must be a three-letter ISO currency code and a supported currency. For example, to define your price in eur, pass the fields below in the eur key of currency_options.
local_product_currency_type = local_product["attributes"]["currency_type"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Currency Type: " "#{local_product_currency_type}"
local_product_shipping_price = local_product["attributes"]["shipping_price"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Shipping Price: " "#{local_product_shipping_price}"
# Same as unit_amount, but accepts a decimal value in cents with at most 12 decimal places. Only one of unit_amount and unit_amount_decimal can be set.
local_product_unit_price = local_product["attributes"]["unit_price"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Unit Price: " "#{local_product_unit_price}"
# TODO
# A label that represents units of this product in Stripe and on customers receipts and invoices. When set, this will be included in associated invoice line item descriptions.
#local_product_unit_label = local_product["attributes"]["unit_label"]
#Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Currency Type: " "#{local_product_unit_label}"
# TODO
# An arbitrary string to be displayed on your customers credit card or bank statement. While most banks display this information consistently, some may display it incorrectly or not at all.
# This may be up to 22 characters. The statement description may not include <, >, \, ", characters, and will appear on your customers statement in capital letters. Non-ASCII characters are automatically stripped. It must contain at least one letter.
#local_product_statement_descriptor = local_product["attributes"]["statement_descriptor"]
#Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Statement Descriptor: " "#{local_product_statement_descriptor}"
# TODO
# Only 8 image URLs per product; loop through each image to get the url
#local_product_images = local_product["attributes"]["gallery"]["data"]["attributes"]["url"]
#Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Gallery Images: " "#{local_product_images}"
local_product_banner_image = local_product["attributes"]["banner_image"]["data"]["attributes"]["url"]
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Product Image: " "#{local_product_banner_image}"
# create data on Stripe API
Stripe::Product.create({
name: "#{local_product_name}",
id: "#{local_product_id}",
description: "#{local_product_description}",
default_price_data: {
currency: "#{local_product_currency_type}",
unit_amount_decimal: "#{local_product_unit_price * 100 }", # format must be in cents e.g. 2000 cents = $20
},
metadata: {build_time: "#{local_conv_modify_time}"},
url: "#{site_endpoint + local_product_webpage_url}",
tax_code: "#{local_product_tax_code}", # must match these codes https://stripe.com/docs/tax/tax-categories
shippable: "#{local_product_is_shippable}",
images: ["#{site_endpoint + local_product_banner_image}"],
# package_dimensions {
# weight: "#{local_product_weight}",
# height: "#{local_product_height}",
# length: "#{local_product_length}",
# width: "#{local_product_width}",
# }
#name: "#{local_product_shipping_rates}",
#name: "#{local_product_shipping_companies}",
#name: "#{local_product_shipping_price}"},
#unit_amount_decimal: "#{local_product_unit_price}",
})
Jekyll.logger.debug "PRODUCT CREATED & POSTED! " "#{local_product_name} \n".to_s.cyan.bold
# check relative stripe product id from each new local_product if error arises
Stripe::Product.retrieve(local_product_id.to_s)
rescue Stripe::InvalidRequestError => e
# Invalid parameters were supplied to Stripe's API
Jekyll.logger.debug "Stripe Error: Invalid API Request - SKIPPING PRODUCT: " "#{local_product_name}".to_s.red
end # begin loop
end # local_product_data
end # if local_product_data.reject...
else
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Remote Product Data is MISSING: ".to_s.yellow.bold
end # filtered_cached_remote_data.present?
end # filter_remote_product_data
else
Jekyll.logger.debug "::DOCUMENT PRODUCT DEBUG:: Local Stripe Data is EMPTY, SKIPPING PRODUCT CREATION! ".to_s.red.bold
end # local_product_data.present?
else
Jekyll.logger.debug "ENV STRIPE DEBUG: Stripe is disabled, enable it in the _config.yml; see docs for more details. " "#{stripe_enabled}".to_s.red.bold
end

View File

@ -1,20 +0,0 @@
---
layout: journal_single
author: Charles #case sensitive, please use capitalization for names.
title: Welcome Home You
sub_heading: Maecenas faucibus mollis interdum. Vivamus sagittis lacus
banner_image: "/assets/images/pic01.jpg" #Size of banner_image 840x341
banner_image_alt: "image alt"
category: Partnerships
tag: Partnerships
---
Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.
Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.

View File

@ -1,20 +0,0 @@
---
layout: journal_single
author: Charles #case sensitive, please use capitalization for names.
title: Welcome Home YOU
sub_heading: A sub_heading for your viewing pleasure
banner_image: "/assets/images/pic02.jpg" #Size of banner_image 840x341
banner_image_alt: "image alt"
category: Partnerships
tag: Partnerships
---
Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.
Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.

View File

@ -1,20 +0,0 @@
---
layout: journal_single
author: Charles #case sensitive, please use capitalization for names.
title: Modern Engineering 2nd Edition
sub_heading: Nullam quis risus eget urna mollis ornare vel eu leo.
banner_image: "/assets/images/pic01.jpg" #Size of banner_image 840x341
banner_image_alt: "image alt"
category: Engineering
tag: Engineering
---
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.
Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.
Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.

View File

@ -1,20 +0,0 @@
---
layout: journal_single
author: Charles #case sensitive, please use capitalization for names.
title: New Industry Partner
sub_heading: Maecenas faucibus mollis interdum. Vivamus sagittis lacus
banner_image: "/assets/images/pic01.jpg" #Size of banner_image 840x341
banner_image_alt: "image alt"
category: Engineering
tag: Partnerships
---
Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.
Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.

View File

@ -1,19 +0,0 @@
---
layout: journal_single
author: Charles #case sensitive, please use capitalization for names.
title: New Research Center
sub_heading: Integer posuere urna mollis ornare vel eu leo.
banner_image: "/assets/images/pic02.jpg" #Size of banner_image 840x341
banner_image_alt: "image alt"
category: Engineering
tag: Research
---
Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.
Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.

View File

@ -1,19 +0,0 @@
---
layout: journal_single
author: Charles #case sensitive, please use capitalization for names.
title: New Research Center
sub_heading: Integer posuere urna mollis ornare vel eu leo.
banner_image: "/assets/images/pic01.jpg" #Size of banner_image 840x341
banner_image_alt: "image alt"
category: Engineering
tag: Research
---
Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.
Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.

View File

@ -1,19 +0,0 @@
---
title: Welcome to the SharpeTronics Demo Site!s
date: 2017-09-25T09:09:13.000+00:00
related_posts:
- _posts/2017-02-12-modern.md
- _posts/2017-08-01-welcome.md
sub_heading: An introduction to SharpeTronics
tags:
- Demo
- Forestry
layout: journal_single
banner_image: ''
---
Welcome to the Belkirk College of Engineering Demo Site!
This site allows you to explore SharpeTronics's features and functionality, and is **not** meant to be used as a production website. To get started building your own site, please see our [documentation](https://sharpetronics.com/help).
Thank you for choosing to demo SharpeTronics!

View File

@ -1,20 +0,0 @@
---
layout: journal_single
author: Charles #case sensitive, please use capitalization for names.
title: Geometry in Fundamental Singularities
sub_heading: Nullam quis risus eget urna mollis ornare vel eu leo.
banner_image: "/assets/images/pic03.jpg" #Size of banner_image 840x341
banner_image_alt: "image alt"
category: Engineering
tag: Engineering
---
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.
Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.
Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.

View File

@ -1,18 +0,0 @@
---
layout: journal_single
author: Charles #case sensitive, please use capitalization for names.
title: Meditation in the Modern Age
sub_heading: A post sub_heading for viewing pleasure
banner_image: "/assets/images/pic02.jpg" #Size of banner_image 840x341
banner_image_alt: "image alt"
category: Research
tag: Demo
---
Mauris neque quam, fermentum ut nisl vitae, convallis maximus nisl. Sed mattis nunc id lorem euismod placerat. Vivamus porttitor magna enim, ac accumsan tortor cursus at. Phasellus sed ultricies mi non congue ullam corper. Praesent tincidunt sed tellus ut rutrum. Sed vitae justo condimentum, porta lectus vitae, ultricies congue gravida diam non fringilla.
Nunc quis dui scelerisque, scelerisque urna ut, dapibus orci. Sed vitae condimentum lectus, ut imperdiet quam. Maecenas in justo ut nulla aliquam sodales vel at ligula. Sed blandit diam odio, sed fringilla lectus molestie sit amet. Praesent eu tortor viverra lorem mattis pulvinar feugiat in turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Fusce ullamcorper tellus sit amet mattis dignissim. Phasellus ut metus ligula. Curabitur nec leo

View File

@ -1,13 +1,15 @@
---
updatedAt: 2022-10-11T22:20:40.674Z
layout: post
title: Our Privacy Policy
subheading: Your data is always yours.
slug: our-privacy-policy
date: 2020-02-03
author: Charles
banner_image: /uploads/terms_48bec2a697.webp
banner_image_alt: An image of a gradient of colours.
title: Our Privacy Policy
sub_heading: Your data is always yours.
tags: Celebration, Privacy, Terms & Conditions,
banner_image_description: an image gradient of blue and white.
category: Legal
tags: Privacy,
---
<h2>Privacy Policy for SharpeTronics.com, Inc.</h2>

View File

@ -1,13 +1,15 @@
---
updatedAt: 2022-10-11T22:20:58.472Z
layout: post
title: Our Terms & Conditions
subheading: Our rules and regulations.
slug: our-terms-and-conditions
date: 2020-02-03
author: Charles
banner_image: /uploads/terms_48bec2a697.webp
banner_image_alt: An image with a gradient of colours.
title: Our Terms & Conditions
sub_heading: Our rules and regulations.
tags: Celebration, Privacy, Terms & Conditions,
banner_image_description: an image gradient of blue and white.
category: Legal
tags: Terms & Conditions,
---
<h2><strong>Terms and Conditions</strong></h2>

View File

@ -1,13 +1,15 @@
---
updatedAt: 2022-10-11T22:16:18.403Z
layout: post
title: Welcome To An Appalachian Technology Company
subheading: Where light travels at high altitudes.
slug: welcome-to-an-appalachian-technology-company
date: 2021-01-03
author: Charles
banner_image: /uploads/wv_seneca_rocks_sky_0d5928baa9.webp
banner_image_alt: WV Sky Seneca Rocks
title: Welcome To An Appalachian Technology Company
sub_heading: Where light travels at high altitudes.
tags: Celebration,
banner_image_description: An image of the night sky in West Virginia.
category: Company
tags: Celebration, Linux, Open Source, Technology,
---
Welcome to SharpeTronics, where light travels at high altitudes. We are a mountain made company in the Appalachians of West Virginia that strives with software and hardware technologies. We are statewide leaders in our area of expertise and invite you to support local business.

View File

@ -1,13 +1,15 @@
---
updatedAt: 2022-10-11T22:27:25.997Z
layout: post
title: Sharpetronics Inc. Becomes Official
subheading: Winding Roads
slug: sharpetronics-inc-becomes-official
date: 2021-03-17
author: Charles
banner_image: /uploads/pillars_face_art_973bf824dd.webp
banner_image_alt: An image of a pillar holding up a building.
title: SharpeTronics Inc. Becomes Official
sub_heading: Winding Roads
tags: Celebration,
banner_image_description: A pillar with a head holding up the ceiling.
category: Company
tags: Contribute, Technology,
---
We as in SharpeTronics Inc. are proud to announce our business is official with the mountain state of West Virginia on March 17, 2021.

View File

@ -1,13 +1,15 @@
---
updatedAt: 2022-10-11T22:12:00.118Z
layout: post
title: Big Startups Without Big Tech
subheading: Liquid Democracy Empowering Network Users
slug: big-startups-without-big-tech
date: 2021-06-29
author: Charles
banner_image: /uploads/decentralized_385bd5a376.webp
banner_image_alt: An image of interconnecting objects
title: Big Startups Without Big Tech
sub_heading: Liquid Democracy Empowering Network Users
tags: Blockchain, Linux,
banner_image_description: Transparent cubes and a high tech lighting backdrop
category: How-to
tags: Blockchain,
---
Welcome to the Blockchain Internet called DFINITY. In my spare time, I have been tinkering and learning **Motoko**. It is a language built for the Internet Computer (IC) that can be used to interface applications, websites and other various software.

View File

@ -1,13 +1,15 @@
---
updatedAt: 2022-10-11T22:10:34.668Z
layout: post
title: Linux VPS Hardening
subheading: Initializing a secure environment
slug: linux-vps-hardening
date: 2021-07-26
author: Charles
banner_image: /uploads/linux_admin_0def8999f2.webp
banner_image_alt: an image of a hooded individual typing on a keyboard
title: Linux VPS Hardening
sub_heading: Initializing a secure environment
tags: Linux, Privacy, Security,
category: How-to
banner_image_description: The back of a black hoodie hacking at software
category: Devops
tags: Linux, VPS, SSL, Security,
---
### Planting Seeds

View File

@ -1,13 +1,15 @@
---
updatedAt: 2022-10-11T22:35:18.838Z
layout: post
title: Configure a Static Qt5 from Source on Ubuntu 18.04 with X11 Support
subheading: Compiling & Configuring Qt from Source
slug: configure-a-static-qt5-from-source-on-ubuntu-18-04-with-x11-support
date: 2021-11-11
author: Charles
banner_image: /uploads/quantum_qt5_95dcd080f1.webp
banner_image_alt: An image of a gold computer circuit.
title: Configure a Static Qt5 from Source on Ubuntu 18.04 with X11 Support
sub_heading: Compiling & Configuring Qt from Source
tags: Linux, VPS, ARM64, AArch64, X11,
category: How-to
banner_image: /uploads/quantum_qt5_41fa19c935.webp
banner_image_description: A golden circuit board.
category: Devops
tags: Linux, Qt5, ARM64, Raspberry Pi 400, X11,
---
### Configure, Build, Install & Setup Qt 5.15.2 Source on Ubuntu 18.04 with X11 Support

View File

@ -1,13 +1,15 @@
---
updatedAt: 2022-10-11T22:07:37.794Z
layout: post
title: Setup a Secure NGINX HTTPS Web Server with Let's Encrypt + Strapi 4.0 Headless CMS
subheading: Static Websites with CMS
slug: setup-a-secure-nginx-https-web-server-with-let-s-encrypt-strapi-4-0-headless-cms
date: 2021-12-27
author: Charles
banner_image: /uploads/santa_rudolph_unsplash_0ae8e3d5a7.webp
banner_image_alt: An image of two pair of holiday cheer feet.
title: Setup a Secure NGINX HTTPS Web Server with Let's Encrypt + Strapi 4.0 Headless CMS
sub_heading: Static Websites with CMS
tags: Nginx, Strapi, Headless CMS, JAMstack,
banner_image_description: Two feet wearing socks beside each other with faces of Santa Clause and another of Rudolph
category: How-to
tags: Nginx, Strapi, SSL, Headless CMS, JAMstack,
---
## General
For this tutorial, we will launch a secure SSL NGINX web server for your website domain example.org and enable an API to be consumed from the subdomain i.e. api.example.org with Strapi 4.0.

View File

@ -1,13 +1,15 @@
---
updatedAt: 2022-10-11T22:35:01.620Z
layout: post
title: Compiling Fresh XMPP Ejabberd Server Binaries 22.05 on Ubuntu 20.04 with Erlang OTP 24
subheading: Creating and host your own end-to-end encryption Instant Messenger app
slug: compiling-fresh-xmpp-ejabberd-server-binaries-22-05-on-ubuntu-20-04-with-erlang-otp-24
date: 2022-06-21
author: Charles
banner_image: /uploads/ejabberd_in_the_jungle_8a9f00e089.webp
banner_image_alt: Compiling Fresh XMPP Ejabberd Server Binaries 22.05 on Ubuntu 20.04 with Erlang OTP 24
title: Compiling Fresh XMPP Ejabberd Server Binaries 22.05 on Ubuntu 20.04 with Erlang OTP 24
sub_heading: Creating and host your own end-to-end encryption Instant Messenger app
tags: Linux, XMPP, Ejabberd,
banner_image_description: A human male swinging above the trees in a jungle.
category: Devops
tags: Privacy, XMPP, Ejabberd,
---
# Compiling ejabberd v22.05
### A XMPP server based on Erlang/OTP 24

View File

@ -1,13 +1,15 @@
---
updatedAt: 2022-10-11T22:04:01.861Z
layout: post
title: How to Setup a Docker Drone CI with HTTPS
subheading: Obiwon Can Oh Be! A digital C3-PO working beside you!
slug: how-to-setup-a-docker-drone-ci-with-https
date: 2022-06-23
author: Charles
banner_image: /uploads/r2d2_skywalker_c84e2364fe.webp
banner_image_alt: Skywalker with R2D2
title: How to Setup a Docker Drone CI with HTTPS
sub_heading: Obiwon Can Oh Be! A digital C3-PO working beside you!
tags: Nginx, Linux, VPS, Drone CI, Docker,
banner_image_description: r2d2 and Luke lego people standing on a laptop
category: How-to
tags: VPS, SSL, Drone CI, Docker,
---
> R2D2, you know better than to trust a strange computer! [beeps]

View File

@ -1,13 +1,15 @@
---
updatedAt: 2022-10-15T21:46:42.406Z
layout: post
title: How to Setup a Secure Docker Drone Runne with Drone CI
subheading: BeeYoop BeeDeepBoom Weeop DEEpaEEya
slug: how-to-setup-a-secure-docker-drone-runne-with-drone-ci
date: 2022-06-23
author: Charles
banner_image: /uploads/c3po_a_friend_in_need_74a237a413.webp
banner_image_alt: Black and white still image of C3PO
title: How to Setup a Secure Docker Drone Runner with Drone CI
sub_heading: BeeYoop BeeDeepBoom Weeop DEEpaEEya
tags: Linux, Drone CI, Docker,
banner_image_description: a picture of c3po from Star Wars
category: How-to
tags: Linux, Drone CI, Docker,
---
> BeeYoop BeeDeepBoom Weeop DEEpaEEya

View File

@ -1,13 +1,15 @@
---
updatedAt: 2022-10-15T18:40:33.689Z
layout: post
title: Update your Strapi CMS with your own Favicon
subheading: How-to replace the favicon
slug: update-your-strapi-cms-with-your-own-favicon
date: 2022-07-12
author: Charles
banner_image: /uploads/code_eff0ff4f77.webp
banner_image_alt: Macguyvering Strapi
title: Update your Strapi CMS with your own Favicon
sub_heading: How-to replace the favicon
tags: Strapi, Configure, Contribute,
banner_image: /uploads/code_2b5ed5fa9c.webp
banner_image_description: computer code matrix
category: How-to
tags: Jekyll, Strapi, Headless CMS,
---
&nbsp;&nbsp;&nbsp;&nbsp;In this article, we will be replacing the Strapi favicon with your own favicon. This same process is similar to how we replace the login logo `AuthLogo` and menu logo with `MenuLogo`. For more details, please visit Strapi documentations example configuration. [Strapi Documents]

View File

@ -1,5 +1,5 @@
---
updatedAt: 2022-10-12T23:07:49.156Z
updatedAt: 2022-10-15T21:18:32.132Z
layout: post
title: Upgrade your Crosshair VI Hero Motherboard Firmware with System76's PopOS!
subheading: I was doing a bit of yak shaving this morning, and it looks like it might have paid off.

View File

@ -1,22 +0,0 @@
---
layout: shop_single
featured: 0 #starred, featured or simple for product pages display sections.
author: Charles #case sensitive, please use capitalization for names.
title: Our Most Recent Rest Product Title
sub_heading: Maecenas faucibus mollis interdum. Vivamus sagittis lacus
banner_image: "/assets/images/pic02.jpg" #Size of banner_image 840x341
banner_image_alt: "image alt"
category: Product
tag: Electronics
---
Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.
Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.

View File

@ -1,23 +0,0 @@
---
layout: shop_single
featured: true #starred, featured or simple for product pages display sections.
record: product-one
author: Charles #case sensitive, please use capitalization for names.
title: Our Most Recent Rest Product Title
sub_heading: Maecenas faucibus mollis interdum. Vivamus sagittis lacus
banner_image: "/assets/images/pic01.jpg" #Size of banner_image 840x341
banner_image_alt: "image alt"
category: Product
tag: Electronics
---
Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.
Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Etiam porta sem malesuada magna mollis euismod.

View File

@ -0,0 +1,36 @@
---
stripe_id: 8
metadata: 2022-10-05T23:44:48+00:00
layout: product
heading: chicken platter
subheading: sadfasdf
slug: chicken-platter
date: 2022-09-01
author: Charles
banner_image: /uploads/terms_48bec2a697.webp
banner_image_description: a short desc. about the banner image
category: How-to
gallery:
- image_path: /uploads/code_2b5ed5fa9c.webp
title: code_2b5ed5fa9c
- image_path: /uploads/r2d2_skywalker_c84e2364fe.webp
title: r2d2_skywalker_c84e2364fe
tags: Jekyll,
webpage_url: https://www.sharpetronics.com/products/2017-02-03-drrragon/
is_featured: false
is_software: true
is_shippable: false
currency_type: USD
country_origin: USA
unit_price: 2
quantity: 2
package_dimensions: 1x1x1mm
material_type: e.g. gold and silver
weight: 1oz
tax_code: txcd_00000000
shipping_price: 2
shipping_rates: Standard
shipping_company: UPS
---
A place to describe the product to your readers. af asd

View File

@ -0,0 +1,36 @@
---
stripe_id: 2
metadata: 2022-10-10T23:34:32+00:00
layout: product
heading: new_product_nameeee
subheading: test again yupy an update
slug: new-product-nameeee
date: 2022-09-13
author: Charles
banner_image: /uploads/optimus_primed_886bcb1942.jpeg
banner_image_description: this is a description
category: Legal
gallery:
- image_path: /uploads/c3po_a_friend_in_need_74a237a413.webp
title: c3po_a_friend_in_need_74a237a413
- image_path: /uploads/r2d2_skywalker_c84e2364fe.webp
title: r2d2_skywalker_c84e2364fe
tags: Strapi, Celebration,
webpage_url: https://www.sharpetronics.com/products/example
is_featured: true
is_software: true
is_shippable: false
currency_type: USD
country_origin: USA
unit_price: 2.5
quantity: 1
package_dimensions: N/a
material_type: e.g. gold and silver
weight: 1.0lb
tax_code: txcd_20030000
shipping_price: 5
shipping_rates: Standard
shipping_company: UPS
---
A place to describe the product to your readers. yay changing the data. changing the data yay more data that isn't saving

View File

@ -0,0 +1,34 @@
---
stripe_id: 7
metadata: 2022-10-02T20:36:28+00:00
layout: product
heading: I am a bananna product
subheading: my sppooon is too beiigg
slug: i-am-a-bananna-product
date: 2022-10-04
author: Charles
banner_image: /uploads/santa_rudolph_unsplash_0ae8e3d5a7.webp
banner_image_description: a short desc. about the banner image
category: Company
gallery:
- image_path: /uploads/c3po_a_friend_in_need_74a237a413.webp
title: c3po_a_friend_in_need_74a237a413
tags: Nginx,
webpage_url: www.dash.sharpetronics.com
is_featured: true
is_software: false
is_shippable: true
currency_type: USD
country_origin: USA
unit_price: 1
quantity: 1
package_dimensions: 1x1x1mm
material_type: gold
weight: 1lb
tax_code: txcd_00000000
shipping_price: 1
shipping_rates: Standard
shipping_company: UPS
---
A place to describe the product to your readers.

View File

@ -0,0 +1,36 @@
---
stripe_id: 5
metadata: 2022-10-11T22:37:24+00:00
layout: product
heading: another productt
subheading: another producttatastasatdfg s
slug: another-productt
date: 2022-10-21
author: Charles
banner_image: /uploads/code_2b5ed5fa9c.webp
banner_image_description: a short desc. about the banner image
category: Legal
gallery:
- image_path: /uploads/code_2b5ed5fa9c.webp
title: code_2b5ed5fa9c
- image_path: /uploads/r2d2_skywalker_c84e2364fe.webp
title: r2d2_skywalker_c84e2364fe
tags:
webpage_url: https://www.sharpetronics.com/products/2017-02-03-dragon
is_featured: true
is_software: true
is_shippable: false
currency_type: USD
country_origin: USA
unit_price: 4
quantity: 3
package_dimensions: 1x1x1mm
material_type: e.g. gold and silver
weight: 3
tax_code: txcd_20030000
shipping_price: 4
shipping_rates: Standard
shipping_company: UPS
---
A place to describe the product to your readers.

View File

@ -73,5 +73,6 @@ services:
ports:
- 4000:4000
environment:
- API_TOKEN=$API_TOKEN
- API_TOKEN=$API_TOKEN,
- STRIPE_LIVE_KEY=$STRIPE_LIVE_KEY
command: jekyll serve --lsi --watch --verbose --trace

View File

@ -30,7 +30,7 @@ SPECIAL THANKS
@YOU
@ajlkn
aj.lkn.io
aj.lkn.io/
@strapijs
strapi.io/
@ -120,9 +120,6 @@ gpl-3.0.en.html
Web Browser Debugging - Testing UI/UX of the website
google.com/chrome/, mozilla.org/en-US/firefox
Stack overflow - Best answers
stackoverflow.com
Startpage - Search engine privacy
startpage.com

43
project.geany Normal file
View File

@ -0,0 +1,43 @@
[editor]
line_wrapping=false
line_break_column=72
auto_continue_multiline=true
[file_prefs]
final_new_line=true
ensure_convert_new_lines=false
strip_trailing_spaces=false
replace_tabs=false
[indentation]
indent_width=4
indent_type=0
indent_hard_tab_width=8
detect_indent=false
detect_indent_width=true
indent_mode=2
[project]
name=SharpeTronics
base_path=/home/csharpe/Desktop/Local-Development/Jekyll/sharpetronics.com/sharpetronics.com
description=
[long line marker]
long_line_behaviour=1
long_line_column=144
[files]
current_page=7
FILE_NAME_0=1664;Ruby;0;EUTF-8;0;1;0;%2Fhome%2Fcsharpe%2FDesktop%2FLocal-Development%2FJekyll%2Fsharpetronics.com%2Fsharpetronics.com%2FGemfile;0;2
FILE_NAME_1=3444;YAML;0;EUTF-8;0;1;0;%2Fhome%2Fcsharpe%2FDesktop%2FLocal-Development%2FJekyll%2Fsharpetronics.com%2Fsharpetronics.com%2F_config.yml;0;2
FILE_NAME_2=0;Ruby;0;EUTF-8;0;1;0;%2Fhome%2Fcsharpe%2FDesktop%2FLocal-Development%2FJekyll%2Fsharpetronics.com%2Fsharpetronics.com%2F_plugins%2Fjekyll-api%2Flib%2Fa-get-collections.rb;0;2
FILE_NAME_3=1641;Ruby;0;EUTF-8;0;1;0;%2Fhome%2Fcsharpe%2FDesktop%2FLocal-Development%2FJekyll%2Fsharpetronics.com%2Fsharpetronics.com%2F_plugins%2Fjekyll-api%2Flib%2Fb-generate-posts.rb;0;2
FILE_NAME_4=6421;Ruby;0;EUTF-8;0;1;0;%2Fhome%2Fcsharpe%2FDesktop%2FLocal-Development%2FJekyll%2Fsharpetronics.com%2Fsharpetronics.com%2F_plugins%2Fjekyll-api%2Flib%2Fb-generate-products.rb;0;2
FILE_NAME_5=17518;Ruby;0;EUTF-8;0;1;0;%2Fhome%2Fcsharpe%2FDesktop%2FLocal-Development%2FJekyll%2Fsharpetronics.com%2Fsharpetronics.com%2F_plugins%2Fjekyll-api%2Flib%2Fc-download-images.rb;0;2
FILE_NAME_6=13355;Ruby;0;EUTF-8;0;1;0;%2Fhome%2Fcsharpe%2FDesktop%2FLocal-Development%2FJekyll%2Fsharpetronics.com%2Fsharpetronics.com%2F_plugins%2Fjekyll-api%2Flib%2Fd-stripe-create-products.rb;0;2
FILE_NAME_7=1593;Markdown;0;EUTF-8;0;1;0;%2Fhome%2Fcsharpe%2FDesktop%2FLocal-Development%2FJekyll%2Fsharpetronics.com%2Fsharpetronics.com%2FREADME.md;0;4
FILE_NAME_8=300;None;0;EUTF-8;0;1;0;%2Fhome%2Fcsharpe%2FDesktop%2FLocal-Development%2FJekyll%2Fsharpetronics.com%2Fsharpetronics.com%2F.env;0;4
FILE_NAME_9=356;YAML;0;EUTF-8;0;1;0;%2Fhome%2Fcsharpe%2FDesktop%2FLocal-Development%2FJekyll%2Fsharpetronics.com%2Fsharpetronics.com%2F.drone.yml;0;4
[VTE]
last_dir=/home/csharpe

View File

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View File

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 KiB

View File

Before

Width:  |  Height:  |  Size: 213 KiB

After

Width:  |  Height:  |  Size: 213 KiB