Moving to microservice client/server model
This commit is contained in:
		
							
								
								
									
										19
									
								
								dsr-input/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								dsr-input/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
# Data Gathering for the @ReachableCEO daily stakeholder report
 | 
			
		||||
 | 
			
		||||
## Introduction
 | 
			
		||||
 | 
			
		||||
I'm trying to life a fully instrumented CTO/founder life and #buildInPublic. And unlike most of the founders doing so, I'm actually publishing daily reports and live streaming my workstation all dya.
 | 
			
		||||
 | 
			
		||||
I want to automate the instrumentation/reporting process as much as possible to get the highest fidelity information for stakeholders consumption.
 | 
			
		||||
 | 
			
		||||
## Data sources
 | 
			
		||||
 | 
			
		||||
- Apple Health (exporting via AutoHealthExport)
 | 
			
		||||
- Workout (evaluating a cou
 | 
			
		||||
- Nutrition
 | 
			
		||||
- Daily habit tracking
 | 
			
		||||
- ActivityWatch
 | 
			
		||||
- WakaAPI
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Scripts
 | 
			
		||||
							
								
								
									
										83
									
								
								dsr-input/dsr-gather-gitea.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								dsr-input/dsr-gather-gitea.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
# Script to query Gitea API for a user's activity on a specific date
 | 
			
		||||
 | 
			
		||||
########################################################################################################
 | 
			
		||||
#Obtain gitea api key from bitwarden
 | 
			
		||||
########################################################################################################
 | 
			
		||||
 | 
			
		||||
####################################
 | 
			
		||||
## Step 0: Set to use tsys server
 | 
			
		||||
####################################
 | 
			
		||||
bw logout
 | 
			
		||||
 | 
			
		||||
echo "Setting cli to use tsys bitwarden server..."
 | 
			
		||||
bw config server https://pwvault.turnsys.com
 | 
			
		||||
 | 
			
		||||
####################################
 | 
			
		||||
## Step 1: login to bitwarden
 | 
			
		||||
####################################
 | 
			
		||||
 | 
			
		||||
# From: https://bitwarden.com/help/cli/#using-an-api-key
 | 
			
		||||
 | 
			
		||||
### Set apikey environment varaible
 | 
			
		||||
 | 
			
		||||
echo "Sourcing clientid/apikey data..."
 | 
			
		||||
source D:/tsys/secrets/bitwarden/data/apikey-bitwarden-reachableceo
 | 
			
		||||
 | 
			
		||||
### Login to vault using apikey...
 | 
			
		||||
 | 
			
		||||
echo "Logging in..."
 | 
			
		||||
bw login --apikey $BW_CLIENTID $BW_CLIENTSECRET
 | 
			
		||||
 | 
			
		||||
### Step 1.1: unlock / save session id 
 | 
			
		||||
 | 
			
		||||
echo "Unlocking..."
 | 
			
		||||
export BW_SESSION="$(bw unlock --passwordenv TSYS_BW_PASSWORD_REACHABLECEO --raw)"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Step 2: retrive a value into an environment variable
 | 
			
		||||
 | 
			
		||||
export GITEA_APIKEY="$(bw get password APIKEY-Gitea)"
 | 
			
		||||
 | 
			
		||||
########################################################################################################
 | 
			
		||||
# Accrss gitea data
 | 
			
		||||
########################################################################################################
 | 
			
		||||
 | 
			
		||||
# Script to query Gitea API for a user's activity on a specific date
 | 
			
		||||
 | 
			
		||||
# Usage: ./get_gitea_user_activity.sh <username> <date> [GITEA_URL] [TOKEN]
 | 
			
		||||
 | 
			
		||||
# Set username, date, and default Gitea URL
 | 
			
		||||
USERNAME="${1:-reachableceo}"                    # Default to "reachableceo" if not provided
 | 
			
		||||
DATE="${2:-$(date +%Y-%m-%d)}"                   # Default to today's date if not provided
 | 
			
		||||
GITEA_URL="${3:-https://git.knownelement.com}"   # Default Gitea URL if not provided
 | 
			
		||||
TOKEN="${GITEA_APIKEY}"                      # Use APIKEY-GItea or passed argument
 | 
			
		||||
 | 
			
		||||
# API Endpoint for user activities
 | 
			
		||||
API_ENDPOINT="$GITEA_URL/api/v1/users/$USERNAME/timeline"
 | 
			
		||||
 | 
			
		||||
# Make the API call
 | 
			
		||||
if [ -n "$TOKEN" ]; then
 | 
			
		||||
  # If token is provided, use it in the Authorization header
 | 
			
		||||
  RESPONSE=$(curl -s -H "Authorization: token $TOKEN" "$API_ENDPOINT")
 | 
			
		||||
else
 | 
			
		||||
  # If no token is provided, make an unauthenticated request
 | 
			
		||||
  RESPONSE=$(curl -s "$API_ENDPOINT")
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Check for API errors
 | 
			
		||||
if [[ "$RESPONSE" == "Not found" || -z "$RESPONSE" ]]; then
 | 
			
		||||
  echo "Error: User '$USERNAME' not found, or endpoint is incorrect."
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Validate JSON response
 | 
			
		||||
if ! echo "$RESPONSE" | jq empty >/dev/null 2>&1; then
 | 
			
		||||
  echo "Error: Invalid JSON response from Gitea API."
 | 
			
		||||
  echo "Response: $RESPONSE"
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Filter the activity by date using jq
 | 
			
		||||
echo "$RESPONSE" | jq --arg date "$DATE" '[.[] | select(.created_at | startswith($date))]'
 | 
			
		||||
							
								
								
									
										59
									
								
								dsr-input/export-joplin-md.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								dsr-input/export-joplin-md.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
# Functions
 | 
			
		||||
 | 
			
		||||
# Search for a note by title and return its ID
 | 
			
		||||
search_note() {
 | 
			
		||||
    local title="$1"
 | 
			
		||||
    echo "Searching for note with title: $title"
 | 
			
		||||
    note_id=$(joplin search "$title" --fields id --limit 1 --json | jq -r '.[0].id')
 | 
			
		||||
    
 | 
			
		||||
    if [[ -z "$note_id" || "$note_id" == "null" ]]; then
 | 
			
		||||
        echo "Error: Note with title '$title' not found."
 | 
			
		||||
        exit 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    echo "Found note with ID: $note_id"
 | 
			
		||||
    echo "$note_id"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Export the note by ID to the specified directory
 | 
			
		||||
export_note() {
 | 
			
		||||
    local note_id="$1"
 | 
			
		||||
    local output_dir="$2"
 | 
			
		||||
 | 
			
		||||
    echo "Exporting note ID: $note_id to directory: $output_dir"
 | 
			
		||||
    mkdir -p "$output_dir" || {
 | 
			
		||||
        echo "Error: Unable to create directory $output_dir"
 | 
			
		||||
        exit 1
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # Export the note with attachments to the specified directory
 | 
			
		||||
    joplin export "$note_id" --format md --output "$output_dir" || {
 | 
			
		||||
        echo "Error: Failed to export note ID $note_id"
 | 
			
		||||
        exit 1
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    echo "Note exported successfully to $output_dir"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Main function
 | 
			
		||||
main() {
 | 
			
		||||
    if [[ $# -lt 2 ]]; then
 | 
			
		||||
        echo "Usage: $0 <note-title> <output-directory>"
 | 
			
		||||
        exit 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    local note_title="$1"
 | 
			
		||||
    local output_dir="$2"
 | 
			
		||||
 | 
			
		||||
    # Search for the note and get its ID
 | 
			
		||||
    local note_id
 | 
			
		||||
    note_id=$(search_note "$note_title")
 | 
			
		||||
 | 
			
		||||
    # Export the note
 | 
			
		||||
    export_note "$note_id" "$output_dir"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Run the main function with all script arguments
 | 
			
		||||
main "$@"
 | 
			
		||||
							
								
								
									
										97
									
								
								dsr-joplin-create/dsr-new.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								dsr-joplin-create/dsr-new.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,97 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
# Use the Joplin CLI and create a new note for today. Let me pass in the notebook folder path. Use bash functions.
 | 
			
		||||
 | 
			
		||||
# Created by chatgpt
 | 
			
		||||
# https://chatgpt.com/share/6750c7df-6b2c-8005-a91c-1bc5b3875170
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# shellcheck disable=SC1090
 | 
			
		||||
 | 
			
		||||
# Bash3 Boilerplate Setup
 | 
			
		||||
set -o errexit
 | 
			
		||||
set -o nounset
 | 
			
		||||
set -o pipefail
 | 
			
		||||
IFS=$'\n\t'
 | 
			
		||||
 | 
			
		||||
# Constants
 | 
			
		||||
readonly SCRIPT_NAME=$(basename "$0")
 | 
			
		||||
readonly SCRIPT_VERSION="1.0"
 | 
			
		||||
readonly SCRIPT_AUTHOR="Charles N Wyble"
 | 
			
		||||
readonly SCRIPT_DESC="Create a new Daily Stakeholder Report note in Joplin"
 | 
			
		||||
 | 
			
		||||
# Logging and Debugging (from bash3boilerplate)
 | 
			
		||||
readonly LOG_FILE="/tmp/${SCRIPT_NAME}.log"
 | 
			
		||||
readonly TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
 | 
			
		||||
info() { echo "[INFO] [$TIMESTAMP] $*"; }
 | 
			
		||||
error() { echo "[ERROR] [$TIMESTAMP] $*" >&2; }
 | 
			
		||||
 | 
			
		||||
# Default Exit Codes
 | 
			
		||||
readonly ERR_JOPLIN_NOT_INSTALLED=10
 | 
			
		||||
readonly ERR_NOTEBOOK_NOT_FOUND=20
 | 
			
		||||
 | 
			
		||||
# Function: Usage Instructions
 | 
			
		||||
usage() {
 | 
			
		||||
    cat <<EOF
 | 
			
		||||
$SCRIPT_DESC
 | 
			
		||||
 | 
			
		||||
Usage:
 | 
			
		||||
  $SCRIPT_NAME <notebook_folder_path>
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
  $SCRIPT_NAME "Stakeholder Reports"
 | 
			
		||||
 | 
			
		||||
Options:
 | 
			
		||||
  -h, --help    Display this help message.
 | 
			
		||||
EOF
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Check dependencies
 | 
			
		||||
require_joplin() {
 | 
			
		||||
    if ! command -v joplin &>/dev/null; then
 | 
			
		||||
        error "Joplin CLI is not installed or not in PATH. Please install it and try again."
 | 
			
		||||
        exit $ERR_JOPLIN_NOT_INSTALLED
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Check if notebook exists in Joplin
 | 
			
		||||
notebook_exists() {
 | 
			
		||||
    local notebook="$1"
 | 
			
		||||
    if ! joplin use "$notebook" >/dev/null 2>&1; then
 | 
			
		||||
        error "Notebook '$notebook' does not exist. Please create it first."
 | 
			
		||||
        exit $ERR_NOTEBOOK_NOT_FOUND
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Create a new note in the specified notebook
 | 
			
		||||
create_note() {
 | 
			
		||||
    local notebook="$1"
 | 
			
		||||
    local today_date=$(date '+%d-%m-%Y') # Format: YYYY-MM-DD
 | 
			
		||||
    local title="Daily Stakeholder Report - $date"
 | 
			
		||||
    local content="## Daily Stakeholder Report\n\n**Date:** $date\n\n---\n\n### Key Updates\n\n- \n\n### Issues\n\n- \n\n### Next Steps\n\n- \n"
 | 
			
		||||
 | 
			
		||||
    joplin create note --title "$title" --body "$content" >/dev/null
 | 
			
		||||
    info "Note created successfully in notebook '$notebook'."
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Main Function
 | 
			
		||||
main() {
 | 
			
		||||
    local notebook_path="$1"
 | 
			
		||||
 | 
			
		||||
    # Ensure Joplin CLI is present
 | 
			
		||||
    require_joplin
 | 
			
		||||
 | 
			
		||||
    # Verify notebook existence
 | 
			
		||||
    notebook_exists "$notebook_path"
 | 
			
		||||
 | 
			
		||||
    # Create a new note
 | 
			
		||||
    create_note "$notebook_path"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Argument Parsing
 | 
			
		||||
if [[ $# -lt 1 ]] || [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then
 | 
			
		||||
    usage
 | 
			
		||||
    exit 0
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
main "$1"
 | 
			
		||||
							
								
								
									
										114
									
								
								dsr-joplin-create/dsr-populate-objectives.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								dsr-joplin-create/dsr-populate-objectives.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
# Written by ChatGPT
 | 
			
		||||
# https://chatgpt.com/share/6750c7df-6b2c-8005-a91c-1bc5b3875170
 | 
			
		||||
 | 
			
		||||
# Prompt:
 | 
			
		||||
# Pull any issues from Redmine that have a due date of today via API
 | 
			
		||||
 | 
			
		||||
# shellcheck disable=SC1090
 | 
			
		||||
 | 
			
		||||
# Bash3 Boilerplate Setup
 | 
			
		||||
set -o errexit
 | 
			
		||||
set -o nounset
 | 
			
		||||
set -o pipefail
 | 
			
		||||
IFS=$'\n\t'
 | 
			
		||||
 | 
			
		||||
# Constants
 | 
			
		||||
readonly SCRIPT_NAME=$(basename "$0")
 | 
			
		||||
readonly SCRIPT_VERSION="1.0"
 | 
			
		||||
readonly SCRIPT_AUTHOR="Charles N Wyble"
 | 
			
		||||
readonly SCRIPT_DESC="Pull Redmine issues with a due date of today and output in Markdown"
 | 
			
		||||
 | 
			
		||||
# Logging and Debugging
 | 
			
		||||
readonly LOG_FILE="/tmp/${SCRIPT_NAME}.log"
 | 
			
		||||
readonly TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
 | 
			
		||||
info() { echo "[INFO] [$TIMESTAMP] $*" | tee -a "$LOG_FILE"; }
 | 
			
		||||
error() { echo "[ERROR] [$TIMESTAMP] $*" >&2 | tee -a "$LOG_FILE"; }
 | 
			
		||||
 | 
			
		||||
# Default Exit Codes
 | 
			
		||||
readonly ERR_CURL_NOT_INSTALLED=10
 | 
			
		||||
readonly ERR_API_FAILURE=20
 | 
			
		||||
 | 
			
		||||
# Configuration
 | 
			
		||||
readonly REDMINE_INSTANCE="projects.knownelement.com"
 | 
			
		||||
readonly REDMINE_API_URL="https://${REDMINE_INSTANCE}"
 | 
			
		||||
readonly REDMINE_API_KEY="your_api_key_here"
 | 
			
		||||
readonly DATE=$(date '+%Y-%m-%d')
 | 
			
		||||
 | 
			
		||||
# Function: Usage Instructions
 | 
			
		||||
usage() {
 | 
			
		||||
    cat <<EOF
 | 
			
		||||
$SCRIPT_DESC
 | 
			
		||||
 | 
			
		||||
Usage:
 | 
			
		||||
  $SCRIPT_NAME <project_id>
 | 
			
		||||
 | 
			
		||||
Options:
 | 
			
		||||
  -h, --help    Display this help message.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
  $SCRIPT_NAME 123
 | 
			
		||||
EOF
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Check dependencies
 | 
			
		||||
require_curl() {
 | 
			
		||||
    if ! command -v curl &>/dev/null; then
 | 
			
		||||
        error "curl is not installed or not in PATH. Please install it and try again."
 | 
			
		||||
        exit $ERR_CURL_NOT_INSTALLED
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Fetch issues from Redmine API
 | 
			
		||||
fetch_issues() {
 | 
			
		||||
    local project_id="$1"
 | 
			
		||||
    local url="${REDMINE_API_URL}/issues.json?key=${REDMINE_API_KEY}&project_id=${project_id}&due_date=${DATE}"
 | 
			
		||||
 | 
			
		||||
    info "Fetching issues with due date ${DATE} for project ID ${project_id}..."
 | 
			
		||||
    response=$(curl -s -w "%{http_code}" -o /tmp/redmine_response.json "$url")
 | 
			
		||||
    http_code=$(tail -n1 <<<"$response")
 | 
			
		||||
 | 
			
		||||
    if [[ "$http_code" -ne 200 ]]; then
 | 
			
		||||
        error "Failed to fetch issues from Redmine API. HTTP Code: $http_code"
 | 
			
		||||
        exit $ERR_API_FAILURE
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    info "Issues fetched successfully. Parsing and converting to Markdown..."
 | 
			
		||||
    generate_markdown /tmp/redmine_response.json
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Generate Markdown output from JSON response
 | 
			
		||||
generate_markdown() {
 | 
			
		||||
    local json_file="$1"
 | 
			
		||||
    local markdown_output="/tmp/redmine_issues.md"
 | 
			
		||||
 | 
			
		||||
    echo "# Redmine Issues for ${DATE}" > "$markdown_output"
 | 
			
		||||
    echo "" >> "$markdown_output"
 | 
			
		||||
 | 
			
		||||
    jq -r --arg base_url "$REDMINE_API_URL" '.issues[] | "## [\(.subject)](\($base_url)/issues/\(.id))\n- **ID**: \(.id)\n- **Status**: \(.status.name)\n- **Due Date**: \(.due_date)\n\n---"' \
 | 
			
		||||
        "$json_file" >> "$markdown_output"
 | 
			
		||||
 | 
			
		||||
    info "Markdown output written to $markdown_output"
 | 
			
		||||
    cat "$markdown_output"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Main Function
 | 
			
		||||
main() {
 | 
			
		||||
    local project_id="$1"
 | 
			
		||||
 | 
			
		||||
    # Ensure curl is installed
 | 
			
		||||
    require_curl
 | 
			
		||||
 | 
			
		||||
    # Fetch issues for the project
 | 
			
		||||
    fetch_issues "$project_id"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Argument Parsing
 | 
			
		||||
if [[ $# -lt 1 ]] || [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then
 | 
			
		||||
    usage
 | 
			
		||||
    exit 0
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
main "$1"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								dsr-publish/2025Plan.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								dsr-publish/2025Plan.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
title: ReachableCEO 2025 Plan
 | 
			
		||||
titlepage: true
 | 
			
		||||
toc: true
 | 
			
		||||
toc-own-page: true
 | 
			
		||||
header-left: "\\hspace{1cm}"
 | 
			
		||||
header-center: "\\leftmark"
 | 
			
		||||
header-right: "Page \\thepage"
 | 
			
		||||
footer-left: "Charles N Wyble"
 | 
			
		||||
footer-center: "Tenacity. Velocity. Focus."
 | 
			
		||||
page-background: "./background5.pdf"
 | 
			
		||||
titlepage-logo: "D:/tsys/@ReachableCEO/ReachableCEO.png"
 | 
			
		||||
urlcolor: blue
 | 
			
		||||
							
								
								
									
										70
									
								
								dsr-publish/background5.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								dsr-publish/background5.pdf
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
%PDF-1.5
 | 
			
		||||
%<25><><EFBFBD><EFBFBD>
 | 
			
		||||
3 0 obj
 | 
			
		||||
<< /Length 4 0 R
 | 
			
		||||
   /Filter /FlateDecode
 | 
			
		||||
>>
 | 
			
		||||
stream
 | 
			
		||||
x<EFBFBD>m<EFBFBD>;<0E>@D<>=<3D>/<2F><><EFBFBD><EFBFBD><EFBFBD>18	<14><>K삢D
 | 
			
		||||
r<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ư<EFBFBD>0f<EFBFBD><EFBFBD>|%<25>߅ <20>1<EFBFBD><31><EFBFBD><EFBFBD>D<EFBFBD><44>g,7<>
 | 
			
		||||
!<21>i<03>jҔ<6A>P	<09>/c<>h<06>px<70>r<72><C289><EFBFBD><EFBFBD>1W<31>^<5E><>Q<EFBFBD>d<>%q<>!<21><>9ZD<12>j<EFBFBD><6A>
 | 
			
		||||
U<EFBFBD>Ѫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>A<EFBFBD>p<EFBFBD><EFBFBD>r$<24>&]x_<78><5F>ʑȽ<CA91>I<EFBFBD>W<><7F>?f<>r)<1F>6EU
 | 
			
		||||
endstream
 | 
			
		||||
endobj
 | 
			
		||||
4 0 obj
 | 
			
		||||
   168
 | 
			
		||||
endobj
 | 
			
		||||
2 0 obj
 | 
			
		||||
<<
 | 
			
		||||
   /ExtGState <<
 | 
			
		||||
      /a0 << /CA 1 /ca 1 >>
 | 
			
		||||
   >>
 | 
			
		||||
>>
 | 
			
		||||
endobj
 | 
			
		||||
5 0 obj
 | 
			
		||||
<< /Type /Page
 | 
			
		||||
   /Parent 1 0 R
 | 
			
		||||
   /MediaBox [ 0 0 595.275574 841.889771 ]
 | 
			
		||||
   /Contents 3 0 R
 | 
			
		||||
   /Group <<
 | 
			
		||||
      /Type /Group
 | 
			
		||||
      /S /Transparency
 | 
			
		||||
      /I true
 | 
			
		||||
      /CS /DeviceRGB
 | 
			
		||||
   >>
 | 
			
		||||
   /Resources 2 0 R
 | 
			
		||||
>>
 | 
			
		||||
endobj
 | 
			
		||||
1 0 obj
 | 
			
		||||
<< /Type /Pages
 | 
			
		||||
   /Kids [ 5 0 R ]
 | 
			
		||||
   /Count 1
 | 
			
		||||
>>
 | 
			
		||||
endobj
 | 
			
		||||
6 0 obj
 | 
			
		||||
<< /Creator (cairo 1.14.8 (http://cairographics.org))
 | 
			
		||||
   /Producer (cairo 1.14.8 (http://cairographics.org))
 | 
			
		||||
>>
 | 
			
		||||
endobj
 | 
			
		||||
7 0 obj
 | 
			
		||||
<< /Type /Catalog
 | 
			
		||||
   /Pages 1 0 R
 | 
			
		||||
>>
 | 
			
		||||
endobj
 | 
			
		||||
xref
 | 
			
		||||
0 8
 | 
			
		||||
0000000000 65535 f 
 | 
			
		||||
0000000582 00000 n 
 | 
			
		||||
0000000282 00000 n 
 | 
			
		||||
0000000015 00000 n 
 | 
			
		||||
0000000260 00000 n 
 | 
			
		||||
0000000354 00000 n 
 | 
			
		||||
0000000647 00000 n 
 | 
			
		||||
0000000774 00000 n 
 | 
			
		||||
trailer
 | 
			
		||||
<< /Size 8
 | 
			
		||||
   /Root 7 0 R
 | 
			
		||||
   /Info 6 0 R
 | 
			
		||||
>>
 | 
			
		||||
startxref
 | 
			
		||||
826
 | 
			
		||||
							
								
								
									
										14
									
								
								dsr-publish/create-2025Plan.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								dsr-publish/create-2025Plan.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
INPUT_FILE="../dsr-build-temp/@DailyStakeholderReports/StrategicPlans/2025-ReachableCEO-Plan.md"
 | 
			
		||||
OUTPUT_FILE="../dsr-build-output/ReachableCEO2025Plan.pdf"
 | 
			
		||||
METADATA_FILE="2025Plan.yml"
 | 
			
		||||
TEMPLATE="eisvogel"
 | 
			
		||||
 | 
			
		||||
pandoc \
 | 
			
		||||
$INPUT_FILE \
 | 
			
		||||
--template $TEMPLATE \
 | 
			
		||||
--metadata-file=$METADATA_FILE \
 | 
			
		||||
--from markdown \
 | 
			
		||||
--to=pdf \
 | 
			
		||||
--output $OUTPUT_FILE
 | 
			
		||||
							
								
								
									
										17
									
								
								dsr-publish/create-dsr-pdf.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								dsr-publish/create-dsr-pdf.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
TODAY_DATE=$(date +%m-%d-%Y)
 | 
			
		||||
INPUT_FILE="DSR-$TODAY_DATE.md"
 | 
			
		||||
OUTPUT_FILE="/d/tsys/@ReachableCEO/DailyStakeholderReport-Pipeline/dsr-build-output/DSR-$TODAY_DATE.pdf"
 | 
			
		||||
METADATA_FILE="/d/tsys/@ReachableCEO/DailyStakeholderReport-Pipeline/dsr-publish/daily-stakeholder-report.yml"
 | 
			
		||||
TEMPLATE="eisvogel"
 | 
			
		||||
 | 
			
		||||
cd /d/tsys/@ReachableCEO/DailyStakeholderReport-Pipeline/dsr-build-temp/@DailyStakeholderReports/Today || exit
 | 
			
		||||
 | 
			
		||||
pandoc \
 | 
			
		||||
$INPUT_FILE \
 | 
			
		||||
--template $TEMPLATE \
 | 
			
		||||
--metadata-file=$METADATA_FILE \
 | 
			
		||||
--from markdown \
 | 
			
		||||
--to=pdf \
 | 
			
		||||
--output $OUTPUT_FILE
 | 
			
		||||
							
								
								
									
										11
									
								
								dsr-publish/daily-stakeholder-report.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								dsr-publish/daily-stakeholder-report.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
title: Daily Stakeholder Report - \today
 | 
			
		||||
urlcolor: blue
 | 
			
		||||
titlepage: true
 | 
			
		||||
header-left: "\\hspace{1cm}"
 | 
			
		||||
header-center: "\\leftmark"
 | 
			
		||||
header-right: "Page \\thepage"
 | 
			
		||||
footer-left: "Charles N Wyble"
 | 
			
		||||
footer-center: "Tenacity. Velocity. Focus."
 | 
			
		||||
footer-right: "[Source code](https://git.knownelement.com/reachableceo/DailyStakeholderReport-Pipeline/src/branch/main/dsr-publish/create-dsr-pdf.sh)"
 | 
			
		||||
page-background: "D:/tsys/@ReachableCEO/DailyStakeholderReport-Pipeline/dsr-publish/background5.pdf"
 | 
			
		||||
titlepage-logo: "D:/tsys/@ReachableCEO/ReachableCEO.png"
 | 
			
		||||
							
								
								
									
										131
									
								
								dsr-publish/publish-dsr.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								dsr-publish/publish-dsr.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,131 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
secrets_manager()
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
echo "Obtaining discourse api key..."
 | 
			
		||||
 | 
			
		||||
bw logout
 | 
			
		||||
 | 
			
		||||
####################################
 | 
			
		||||
## Step 0: Set to use tsys server
 | 
			
		||||
####################################
 | 
			
		||||
bw config server https://pwvault.turnsys.com
 | 
			
		||||
 | 
			
		||||
####################################
 | 
			
		||||
## Step 1: login to bitwarden
 | 
			
		||||
####################################
 | 
			
		||||
 | 
			
		||||
# From: https://bitwarden.com/help/cli/#using-an-api-key
 | 
			
		||||
 | 
			
		||||
### Set apikey environment varaible
 | 
			
		||||
 | 
			
		||||
source D:/tsys/secrets/bitwarden/data/apikey-bitwarden-reachableceo
 | 
			
		||||
 | 
			
		||||
### Login to vault using apikey...
 | 
			
		||||
 | 
			
		||||
bw login --apikey $BW_CLIENTID $BW_CLIENTSECRET
 | 
			
		||||
 | 
			
		||||
### Step 1.1: unlock / save session id 
 | 
			
		||||
 | 
			
		||||
export BW_SESSION="$(bw unlock --passwordenv TSYS_BW_PASSWORD_REACHABLECEO --raw)"
 | 
			
		||||
 | 
			
		||||
### Step 2: retrive a value into an environment variable
 | 
			
		||||
 | 
			
		||||
export DISCOURSE_APIKEY="$(bw get password APIKEY-discourse)"
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
post_dsr()
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
TODAY_DATE=$(date +%m-%d-%Y)
 | 
			
		||||
 | 
			
		||||
echo "Posting DSR..."
 | 
			
		||||
 | 
			
		||||
DISCOURSE_URL="https://community.turnsys.com"  # e.g., https://forum.example.com
 | 
			
		||||
API_KEY="$DISCOURSE_APIKEY" # Your API key
 | 
			
		||||
API_USERNAME="reachableceo" # API username or admin account
 | 
			
		||||
 | 
			
		||||
# The category ID to post to (update to match your forum's categories)
 | 
			
		||||
CATEGORY_ID=61
 | 
			
		||||
 | 
			
		||||
# The title for the post (generated here; customize as needed)
 | 
			
		||||
TITLE="Daily Stakeholder Report - $TODAY_DATE"
 | 
			
		||||
 | 
			
		||||
# The content of the post
 | 
			
		||||
CONTENT="Please use the link below to download today's stakeholder report."
 | 
			
		||||
 | 
			
		||||
# The file to upload (from the second argument or auto-generated based on date)
 | 
			
		||||
FILE_PATH="../dsr-build-output/DSR-$TODAY_DATE.pdf"
 | 
			
		||||
 | 
			
		||||
# Check if the file exists
 | 
			
		||||
if [ ! -f "$FILE_PATH" ]; then
 | 
			
		||||
  echo "File not found: $FILE_PATH"
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Upload the file
 | 
			
		||||
echo "Uploading file..."
 | 
			
		||||
upload_response=$(curl -s -X POST "$DISCOURSE_URL/uploads.json" \
 | 
			
		||||
  -H "Content-Type: multipart/form-data" \
 | 
			
		||||
  -H "Api-Key: $API_KEY" \
 | 
			
		||||
  -H "Api-Username: $API_USERNAME" \
 | 
			
		||||
  -F "file=@$FILE_PATH;type=application/pdf" \
 | 
			
		||||
  -F "type=composer")
 | 
			
		||||
 | 
			
		||||
echo "Upload Response: $upload_response"
 | 
			
		||||
 | 
			
		||||
# Extract the short_url from the response
 | 
			
		||||
short_url=$(echo "$upload_response" | /mingw64/bin/jq -r '.short_url')
 | 
			
		||||
 | 
			
		||||
# Check if the short_url was returned
 | 
			
		||||
if [ "$short_url" == "null" ]; then
 | 
			
		||||
  echo "Failed to extract short_url. Response:"
 | 
			
		||||
  echo "$upload_response"
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo "File uploaded successfully. Short URL: $short_url"
 | 
			
		||||
 | 
			
		||||
# Append the file link to the post content (Markdown format)
 | 
			
		||||
CONTENT="$CONTENT\n\n[Download todays report in PDF format]($short_url)"
 | 
			
		||||
 | 
			
		||||
# Create the new topic
 | 
			
		||||
echo "Creating new topic..."
 | 
			
		||||
post_response=$(curl -s -X POST "$DISCOURSE_URL/posts.json" \
 | 
			
		||||
  -H "Content-Type: application/json" \
 | 
			
		||||
  -H "Api-Key: $API_KEY" \
 | 
			
		||||
  -H "Api-Username: $API_USERNAME" \
 | 
			
		||||
  -d @- <<EOF
 | 
			
		||||
{
 | 
			
		||||
  "title": "$TITLE",
 | 
			
		||||
  "raw": "$CONTENT",
 | 
			
		||||
  "category": $CATEGORY_ID
 | 
			
		||||
}
 | 
			
		||||
EOF
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
echo "Post Response: $post_response"
 | 
			
		||||
 | 
			
		||||
# Check if the post creation was successful
 | 
			
		||||
if echo "$post_response" | grep -q '"id":'; then
 | 
			
		||||
  echo "Post created successfully!"
 | 
			
		||||
else
 | 
			
		||||
  echo "Failed to create post. Response:"
 | 
			
		||||
  echo "$post_response"
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Get discourse api key
 | 
			
		||||
 | 
			
		||||
secrets_manager 
 | 
			
		||||
 | 
			
		||||
# - Create a new topic 
 | 
			
		||||
# - upload PDF to discourse
 | 
			
		||||
# - attach uploaded PDF to the topic
 | 
			
		||||
 | 
			
		||||
post_dsr
 | 
			
		||||
							
								
								
									
										35
									
								
								endstops/end-day.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								endstops/end-day.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
# Wrap up my instrumented day into a (mostly) automated report and publish to discourse
 | 
			
		||||
 | 
			
		||||
# Gather DSR assets
 | 
			
		||||
 | 
			
		||||
# My manually entered notations
 | 
			
		||||
./dsr-input/dsr-gather-joplin-log.sh
 | 
			
		||||
 | 
			
		||||
# My gitea data
 | 
			
		||||
./dsr-input/dsr-gather-gitea.sh
 | 
			
		||||
 | 
			
		||||
# My redmine data
 | 
			
		||||
./dsr-input/dsr-gather-redmine.sh
 | 
			
		||||
 | 
			
		||||
# My wakapi data
 | 
			
		||||
./dsr-input/dsr-gather-waka-api.sh
 | 
			
		||||
 | 
			
		||||
# My activity watch data
 | 
			
		||||
./dsr-input/dsr-gather-activitywatch.sh
 | 
			
		||||
 | 
			
		||||
# My habit tracker data
 | 
			
		||||
./dsr-input/dsr-gather-habits.sh
 | 
			
		||||
 | 
			
		||||
# My health/fitnes data 
 | 
			
		||||
./dsr-input/dsr-gather-fitness.sh
 | 
			
		||||
 | 
			
		||||
# My diet data
 | 
			
		||||
./dsr-input/dsr-gather-diet.sh
 | 
			
		||||
 | 
			
		||||
# Produce DSR PDF asset
 | 
			
		||||
./dsr-publish/create-dsr-pdf.sh
 | 
			
		||||
 | 
			
		||||
# Publish DSR to the world
 | 
			
		||||
./dsr-publish/publish-dsr.sh
 | 
			
		||||
							
								
								
									
										9
									
								
								endstops/start-day.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								endstops/start-day.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
# Start my instrumented day 
 | 
			
		||||
 | 
			
		||||
# Create a new blank DSR for the day 
 | 
			
		||||
./dsr-joplin-create/dsr-new.sh
 | 
			
		||||
 | 
			
		||||
# Populate my Joplin note "Todays objectives" section based on Redmine due dates
 | 
			
		||||
./dsr-joplin-create/dsr-populate-objectives.sh
 | 
			
		||||
		Reference in New Issue
	
	Block a user