Script to batch update OU bookmarks (GAMADV-XTD3)

44 views
Skip to first unread message

Wes Hall

unread,
Sep 10, 2024, 12:55:57 PM9/10/24
to GAM for Google Workspace
I love the idea of James' Sheet solution (https://sites.google.com/jis.edu.bn/gam-commands/hardware/chrome#h.tmi7gjxr11ie) for keeping bookmarks in a desired order, but I don't like having to manually tweak the resulting almost_json.

I may come back to his sheet and work on a method to query it and update programmatically (imagine teachers updating their bookmarks in a shared Sheet and a script running every night to sync changes...) , but in the mean time, I whipped up this script. 

Everything resides in one document and ordering is preserved, as best as possible.  It doesn't currently support more than one folder depth, but is designed to be quick to work with.  When a new bookmark is needed, add the information (name, url, and desired folder name, if one) and run the script.

In our use case (K-12), students are organized by graduating year.  This means 4th grade exists in a different OU every year.  Your use case may not need this, but I don't want to have to remember how to move everything every summer.  Hopefully that explains the additional complexity.

This has been a wonderful community to join and I appreciate all of the time-saving hints that I've discovered over the last 6 months.  Hopefully this will be of use to somebody!  Let me know if I broke something when sanitizing the code copy.

#! /usr/bin/python3
# -*- coding: utf-8 -*-
#
# set_bookmarks.py
from copy import deepcopy
from datetime import datetime
import json
import subprocess
from pathlib import Path, PurePath

TEST_MODE = True
DELETE_JSON = False

GAM_BIN = '/?????/bin/gamadv-xtd3/gam' # your gam path if python doesn't find it.
OU_STUDENTS ='/Students/'

BASE_POLICY = {
"additionalTargetKeys": [],
"direct": True,
"fields": [{"name": "managedBookmarks","value": {"bookmarks": []}}],
"name": "chrome.users.ManagedBookmarksSetting",
}

bookmarks = [
{
"grade": 3,
"name": "3rd Grade Bookmarks",
"links": [
{"name": "Schoology", "url": "https://schoology.com/"},
],
},
{
"grade": 4,
"test_ou": False, # Toggle True to test this ou when in TEST_MODE
"name": "4th Grade Bookmarks",
"links": [ # The first few are expanded to see the folder option
{
"name": "Schoology",
},
{
"name": "Jeopardy Labs",
"folder": "Websites"
},
{
"name": "IXL Math",
"folder": "Websites"
},
{"name": "Seterra Geography", "url": "https://www.seterra.com/#quizzes", "folder": "Websites"},
{"name": "Kahoot!", "url": "https://kahoot.it/", "folder": "Websites"},
{"name": "Microsoft Word", "url": "https://www.microsoft365.com/launch/word?auth=2", "folder": "Word Processing"},
{"name": "Google Docs", "url": "https://docs.google.com/", "folder": "Word Processing"},
{"name": "MAP Testing - NWEA", "url": "https://test.mapnwea.org/"},
]
},
{
"grade": 12,
"name": "Senior Bookmarks",
"links": [
{"name": "PowerSchool", "url": "https://powerschool.com/"},
{"name": "Schoology", "url": "https://schoology.com/"},
],
},
]


def get_grade_year(grade):
if type(grade) == str:
if grade.lower() == 'k':
grade = 0
elif grade.lower() == 'pk':
grade = -1
else:
grade = -2
if datetime.now().month > 6: # If in the fall, adjust for next calendar year
return datetime.now().year + 13 - grade
else:
return datetime.now().year + 12 - grade


def get_working_ou(grade):
"""Update as necessary for complicated OU assignments"""
grade_year = get_grade_year(grade)
return str(PurePath(OU_STUDENTS, str(grade_year)))


if __name__ == "__main__":
for ou_bookmarks in bookmarks:
bookmark_order = list()
bookmark_folders = dict()
ou = get_working_ou(ou_bookmarks['grade'])
policy = deepcopy(BASE_POLICY)
policy['orgUnitPath'] = ou
policy['parentOrgUnitPath'] = ou
for link in ou_bookmarks['links']:
if link.get('folder', None) is None:
bookmark_order.append(link)
elif link['folder'] not in bookmark_order:
bookmark_order.append(link['folder'])
bookmark_folders[link['folder']] = list()
bookmark_folders[link['folder']].append(link)
else:
bookmark_folders[link['folder']].append(link)
for b in bookmark_order:
if b in [x for x in bookmark_folders]:
new_entry = {"folder": {"entries": list(), "name":b}}
for bl in bookmark_folders[b]:
new_entry["folder"]["entries"].append(
{"link": { x:y for x,y in bl.items() if x in ['name','url']}})
policy['fields'][0]['value']['bookmarks'].append(new_entry)
else:
policy['fields'][0]['value']['bookmarks'].append({"link": b})
policy['fields'][0]['value']['toplevelName'] = ou_bookmarks['name']
fname = f"temp_{get_grade_year(ou_bookmarks['grade'])}_policy.json"
with open(fname, 'w', encoding='utf-8') as temp_json_file:
json.dump(policy, temp_json_file, ensure_ascii=False, indent=4)
if (not TEST_MODE) or (ou_bookmarks.get('test_ou', False)):
subprocess.run([
GAM_BIN,'update','chromepolicy',
'chrome.users.ManagedBookmarksSetting',
'json','file',fname,'orgunit',ou])
if DELETE_JSON:
Path.unlink(fname)


##
GAC, Chrome, Policy, GAM, Bookmarks
Reply all
Reply to author
Forward
0 new messages