Files
claudetools/clients/dataforth/docs/projects/shares-permissions/_build_docx.py
Howard Enos 83133ddce3 sync: auto-sync from HOWARD-HOME at 2026-06-10 20:21:07
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-10 20:21:07
2026-06-10 20:21:23 -07:00

266 lines
12 KiB
Python

#!/usr/bin/env python3
"""Build the Dataforth Shared Drives Reorganization & Access Plan (.docx)."""
import os
from docx import Document
from docx.shared import Pt, RGBColor, Inches
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
NAVY = RGBColor(0x1F, 0x39, 0x64)
ACCENT = RGBColor(0x2E, 0x74, 0xB5)
RED = RGBColor(0xB0, 0x20, 0x20)
GREY = RGBColor(0x59, 0x59, 0x59)
HDR_FILL = "1F3964"
SENS_FILL = "FBE4E4"
ALT_FILL = "F2F6FB"
doc = Document()
# Base style
normal = doc.styles["Normal"]
normal.font.name = "Calibri"
normal.font.size = Pt(11)
normal.paragraph_format.space_after = Pt(6)
for hs, sz, col in [("Heading 1", 15, NAVY), ("Heading 2", 12.5, ACCENT)]:
st = doc.styles[hs]
st.font.name = "Calibri"
st.font.size = Pt(sz)
st.font.color.rgb = col
st.font.bold = True
def shade(cell, fill):
tcPr = cell._tc.get_or_add_tcPr()
shd = OxmlElement("w:shd")
shd.set(qn("w:val"), "clear")
shd.set(qn("w:fill"), fill)
tcPr.append(shd)
def set_cell_text(cell, text, bold=False, color=None, size=10.5, align=None):
cell.text = ""
p = cell.paragraphs[0]
if align:
p.alignment = align
run = p.add_run(text)
run.font.size = Pt(size)
run.font.bold = bold
if color:
run.font.color.rgb = color
def header_row(table, labels):
for i, lab in enumerate(labels):
c = table.rows[0].cells[i]
set_cell_text(c, lab, bold=True, color=RGBColor(0xFF, 0xFF, 0xFF))
shade(c, HDR_FILL)
def add_table(headers, rows, widths=None, sensitive_rows=None):
sensitive_rows = sensitive_rows or set()
t = doc.add_table(rows=1, cols=len(headers))
t.alignment = WD_TABLE_ALIGNMENT.CENTER
t.style = "Table Grid"
header_row(t, headers)
for r_idx, row in enumerate(rows):
cells = t.add_row().cells
for i, val in enumerate(row):
set_cell_text(cells[i], val)
if r_idx in sensitive_rows:
for c in cells:
shade(c, SENS_FILL)
elif r_idx % 2 == 1:
for c in cells:
shade(c, ALT_FILL)
if widths:
for row in t.rows:
for i, w in enumerate(widths):
row.cells[i].width = Inches(w)
return t
def spacer(pts=4):
p = doc.add_paragraph()
p.paragraph_format.space_after = Pt(pts)
# ---- Title block ----
title = doc.add_paragraph()
title.alignment = WD_ALIGN_PARAGRAPH.LEFT
r = title.add_run("Dataforth Shared Drives")
r.font.size = Pt(24); r.font.bold = True; r.font.color.rgb = NAVY
sub = doc.add_paragraph()
r = sub.add_run("Reorganization & Access Plan")
r.font.size = Pt(15); r.font.color.rgb = ACCENT
meta = doc.add_paragraph()
r = meta.add_run("Prepared by Arizona Computer Guru · June 2026")
r.font.size = Pt(10); r.font.color.rgb = GREY; r.italic = True
# rule
pr = doc.add_paragraph()
pbdr = OxmlElement("w:pPr"); bdr = OxmlElement("w:pBdr")
bottom = OxmlElement("w:bottom")
bottom.set(qn("w:val"), "single"); bottom.set(qn("w:sz"), "12")
bottom.set(qn("w:space"), "1"); bottom.set(qn("w:color"), "2E74B5")
bdr.append(bottom); pbdr.append(bdr)
pr._p.insert(0, pbdr)
# ---- Intro ----
doc.add_paragraph(
"This document explains how Dataforth's shared network drives are organized today, why we "
"recommend changing that, and what a cleaner, department-based setup would look like. The goal "
"is simple: keep files organized by department, give each team access to what it needs, and "
"protect sensitive information — without anyone losing access to the files they use day to day."
)
note = doc.add_paragraph()
r = note.add_run("Nothing will change until you have reviewed and approved a plan. We will make changes "
"in stages so the transition is smooth.")
r.italic = True; r.font.color.rgb = GREY
# ---- Section 1: situation today ----
doc.add_heading("1. The situation today", level=1)
doc.add_paragraph(
"Right now, every shared drive at Dataforth is open to every employee. Anyone who logs in can "
"open, change, move, or delete files on all of them — there are no department-level "
"restrictions in place."
)
doc.add_paragraph(
"Think of it like a building where every filing cabinet is unlocked: convenient, but it means "
"payroll records, employee safety files, purchase orders, and the accounting books are all sitting "
"open to everyone in the company. It also makes accidental changes or deletions easy, and if a "
"single employee account is ever compromised, that account can reach everything at once."
)
doc.add_paragraph(
"On top of access, the drives have simply grown messy over the years — the same files in "
"multiple places, folders named “Do not use,” and personal folders left behind by former "
"employees. Files are arranged by history, not by department."
)
# ---- Section 2: what we recommend ----
doc.add_heading("2. What we recommend", level=1)
for b in [
"Organize files by department, so each team's data lives in one clear place.",
"Give each department access to only the folders it needs — full access where they work, "
"view-only where they just need to reference, and no access to areas that don't concern them.",
"Lock down sensitive data (payroll, employee/OSHA records, purchase orders, accounting) so only "
"the right people can see it.",
"Clean up duplicate, outdated, and orphaned folders as we go (with your approval before anything "
"is removed).",
"Set it up so access is easy to manage going forward — adding a new hire becomes “put them "
"in the Sales group” rather than hand-setting permissions folder by folder.",
]:
doc.add_paragraph(b, style="List Bullet")
# ---- Section 3: current drives ----
doc.add_heading("3. Your shared drives today", level=1)
doc.add_paragraph("Here is what is on each shared drive now. Drives marked with a red row contain "
"sensitive information that should not be open to all staff.")
rows = [
["Q: (“c-drive”)", "General company files: documents, manufacturing, production control, shipping, scanned documents — plus Payroll, OSHA records, and Purchase Orders", "Yes"],
["T: (“e-drive”)", "Engineering & manufacturing files (ENGR, ECOs, FMEA, Test Engineering) — plus QuickBooks accounting files", "Yes"],
["S: (“sage”)", "Sage accounting system, invoices, and financial reports", "Yes"],
["W: (“sales”)", "Sales & marketing materials, contacts, RMAs, videos", "No"],
["Y: (“archive”)", "Archived engineering data", "No"],
["B: (“Engineering”)", "The main, large Engineering data store", "No"],
["itsvc", "IT software, drivers, and server tools (used by IT)", "No"],
["X: (“webshare”)", "Files for the automated website datasheet system (mostly automated)", "No"],
]
sens = {i for i, row in enumerate(rows) if row[2] == "Yes"}
add_table(["Drive", "What's on it today", "Sensitive?"], rows, widths=[1.3, 5.0, 0.9], sensitive_rows=sens)
small = doc.add_paragraph()
r = small.add_run("There is also a “test” drive used by the DOS test stations on the manufacturing "
"floor. It must stay exactly as it is for those machines to keep working, so it is not "
"part of this reorganization.")
r.font.size = Pt(9.5); r.italic = True; r.font.color.rgb = GREY
# ---- Section 4: proposed structure ----
doc.add_heading("4. A cleaner structure — organized by department", level=1)
doc.add_paragraph(
"Instead of a handful of catch-all drives that everyone can see, we propose organizing the data "
"into clear department areas. Each area would have its own access list. The areas marked "
"“restricted” would be limited to specific people or departments."
)
prop = [
["Company (All Staff)", "Company-wide documents, forms, policies, templates, announcements", "Everyone"],
["Engineering", "Engineering files, ECOs, FMEA, test engineering, engineering archive", "Engineering"],
["Manufacturing & Production", "Manufacturing, production control, SMT, assembly documents", "Manufacturing"],
["Quality & Calibration", "Quality records, calibration, inspection data", "Quality"],
["Sales & Marketing", "Sales materials, contacts, RMAs, marketing", "Sales"],
["Shipping & Receiving", "Shipping paperwork, receiving, RMA handoffs", "Shipping"],
["Accounting & Finance (restricted)", "Sage, QuickBooks, invoices, purchase orders, financial reports", "Accounting only"],
["Human Resources (restricted)", "Payroll, OSHA 300, safety training, personnel files", "HR only"],
["IT (restricted)", "IT software, drivers, server tools", "IT only"],
]
restricted = {6, 7, 8}
add_table(["Proposed department area", "What would live here", "Primary owner"], prop,
widths=[2.4, 3.8, 1.3], sensitive_rows=restricted)
# ---- Section 5: where things move ----
doc.add_heading("5. Where today's sensitive items would move", level=1)
doc.add_paragraph("A few concrete examples of how today's exposed folders would be relocated and protected:")
moves = [
["Payroll", "Q: (open to all)", "Human Resources (restricted)"],
["OSHA 300 / Safety Training", "Q: (open to all)", "Human Resources (restricted)"],
["Purchase Orders", "Q: (open to all)", "Accounting & Finance (restricted)"],
["QuickBooks files (QBfiles)", "T: (open to all)", "Accounting & Finance (restricted)"],
["Sage accounting", "S: (open to all)", "Accounting & Finance (restricted)"],
["Engineering (ENGR, ECOs, FMEA)", "Spread across T:, Y:, B:", "Engineering"],
["“Do not use” / old / personal folders", "Various drives", "Archived or removed (with your OK)"],
]
add_table(["Item", "Where it is now", "Proposed new home"], moves, widths=[2.6, 2.3, 2.6])
# ---- Section 6: what we need ----
doc.add_heading("6. What we need from you", level=1)
doc.add_paragraph("To build the plan, please help us with the following. A short call works too if that's easier.")
for b in [
"Confirm your department list (the areas in Section 4 are our starting guess).",
"Fill in the access plan below — who should be able to add/edit files in each area, and who only "
"needs to view them.",
"Tell us exactly who should have access to the restricted areas (Accounting, HR, IT).",
"Provide a list of employees by department (or an org chart) so we can set up the groups.",
"Let us know of any old folders you already know are safe to clean up.",
]:
doc.add_paragraph(b, style="List Bullet")
doc.add_heading("Access plan — please fill in", level=2)
doc.add_paragraph("For each area, write which departments (or people) need full access vs. view-only. "
"Anyone not listed simply won't have access to that area.")
acc = [
["Company (All Staff)", "All staff", ""],
["Engineering", "", ""],
["Manufacturing & Production", "", ""],
["Quality & Calibration", "", ""],
["Sales & Marketing", "", ""],
["Shipping & Receiving", "", ""],
["Accounting & Finance (restricted)", "", ""],
["Human Resources (restricted)", "", ""],
["IT (restricted)", "", ""],
]
t = add_table(["Department area", "Full access (add / edit)", "View-only"], acc,
widths=[2.4, 2.8, 2.3], sensitive_rows={6, 7, 8})
# give the fill-in rows a little height
for row in t.rows[1:]:
trPr = row._tr.get_or_add_trPr()
h = OxmlElement("w:trHeight"); h.set(qn("w:val"), "420"); h.set(qn("w:hRule"), "atLeast")
trPr.append(h)
# ---- Section 7: how we do it safely ----
doc.add_heading("7. How we'll do this safely", level=1)
for b in [
"We start from your answers and send back a clear “who sees what” plan for your sign-off.",
"Nothing changes until you approve it.",
"We make the changes in stages, one area at a time, and confirm each department can still reach "
"their files before moving on.",
"If anyone is missing access after a change, it's a quick fix — we add them to the right group.",
"We keep a full backup of the current setup so any change can be reversed.",
]:
doc.add_paragraph(b, style="List Bullet")
doc.add_paragraph()
close = doc.add_paragraph()
r = close.add_run("Questions or want to walk through this together? We're happy to jump on a call.")
r.italic = True; r.font.color.rgb = GREY
out = os.path.join(os.path.dirname(os.path.abspath(__file__)),
"Dataforth-Shared-Drives-Reorganization-Plan.docx")
doc.save(out)
print("WROTE:", out)
print("paragraphs:", len(doc.paragraphs), "tables:", len(doc.tables))