Compare commits
No commits in common. "5b8d24f2a6c551d74e537b5942af115f8f656a8d" and "91fd6c2f439fbbec702d6364fa32380f08f897ba" have entirely different histories.
5b8d24f2a6
...
91fd6c2f43
11
README.md
11
README.md
|
|
@ -1,6 +1,6 @@
|
||||||
# Calendar plugin for wordpress site
|
# Calendar plugin for wordpress site
|
||||||
|
|
||||||
## Bugs
|
Status as of 2026-03-31 when codex credit ran out:
|
||||||
|
|
||||||
1. Removal of plugin did not work. Need to set all files owner to www-data. - done
|
1. Removal of plugin did not work. Need to set all files owner to www-data. - done
|
||||||
2. Deletion of event in ui doesn't delete event in thunderbird - done
|
2. Deletion of event in ui doesn't delete event in thunderbird - done
|
||||||
|
|
@ -10,11 +10,4 @@
|
||||||
6. Updating an events description via caldav creates weird sequences, e.g.
|
6. Updating an events description via caldav creates weird sequences, e.g.
|
||||||
a space ends up as: text/html,%C2%A0":
|
a space ends up as: text/html,%C2%A0":
|
||||||
7. In a private window, Click on event from not-logged-in calendar page shows event as a dialog box, it should show it as a panel with a subset of the edit event panel - i.e. the title, category, location, start and end and description. -
|
7. In a private window, Click on event from not-logged-in calendar page shows event as a dialog box, it should show it as a panel with a subset of the edit event panel - i.e. the title, category, location, start and end and description. -
|
||||||
8. Thunderbird cutting/pasting/moving events is - TBD.#
|
8.
|
||||||
|
|
||||||
|
|
||||||
## Enhancements
|
|
||||||
|
|
||||||
Calendar sidebar, hide description if there is one, but present an expansion "caret".
|
|
||||||
|
|
||||||
List mode view, list or configure data range of display.
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
* Plugin Name: Calendar Plugin
|
* Plugin Name: Calendar Plugin
|
||||||
* Plugin URI: https://chezstephens.org.uk
|
* Plugin URI: https://chezstephens.org.uk
|
||||||
* Description: Provides a single shared calendar for WordPress with public display, authenticated event editing, user approval workflow, ICS publishing, and CalDAV read/write sync. Supports recurring events, single-occurrence exceptions, admin setup and diagnostics pages, and shortcode rendering for full calendar and upcoming-events sidebar views.
|
* Description: Provides a single shared calendar for WordPress with public display, authenticated event editing, user approval workflow, ICS publishing, and CalDAV read/write sync. Supports recurring events, single-occurrence exceptions, admin setup and diagnostics pages, and shortcode rendering for full calendar and upcoming-events sidebar views.
|
||||||
* Version: 1.0.2
|
* Version: 1.0.1
|
||||||
* Requires at least: 6.0
|
* Requires at least: 6.0
|
||||||
* Requires PHP: 8.1
|
* Requires PHP: 8.1
|
||||||
* Author: Adrian Stephens (with AI assistance)
|
* Author: Adrian Stephens (with AI assistance)
|
||||||
|
|
|
||||||
|
|
@ -1019,7 +1019,7 @@ HTML
|
||||||
$end = (string) ($item['occurrence_end'] ?? '');
|
$end = (string) ($item['occurrence_end'] ?? '');
|
||||||
$startDt = $this->toSidebarDateTime($start, $sidebarTz);
|
$startDt = $this->toSidebarDateTime($start, $sidebarTz);
|
||||||
$endDt = $this->toSidebarDateTime($end, $sidebarTz);
|
$endDt = $this->toSidebarDateTime($end, $sidebarTz);
|
||||||
$dateLabel = $startDt !== null ? $startDt->format('l j F Y') : substr($start, 0, 10);
|
$dateLabel = $startDt !== null ? $startDt->format('j F Y') : substr($start, 0, 10);
|
||||||
$timeLabel = '';
|
$timeLabel = '';
|
||||||
if ($startDt !== null && $endDt !== null) {
|
if ($startDt !== null && $endDt !== null) {
|
||||||
$startTime = $startDt->format('H:i');
|
$startTime = $startDt->format('H:i');
|
||||||
|
|
@ -1422,7 +1422,7 @@ HTML
|
||||||
return [
|
return [
|
||||||
'status' => 'ok',
|
'status' => 'ok',
|
||||||
'plugin' => 'calendar-plugin',
|
'plugin' => 'calendar-plugin',
|
||||||
'version' => '1.0.2',
|
'version' => '1.0.1',
|
||||||
'db_prefix' => $this->db->getPrefix(),
|
'db_prefix' => $this->db->getPrefix(),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -340,20 +340,7 @@ $sluggedCalendarHtml = do_shortcode('[calendar]');
|
||||||
assert_true(str_contains($sluggedCalendarHtml, 'href="/events/calendar.ics"'), 'calendar shortcode should use slugged ICS path');
|
assert_true(str_contains($sluggedCalendarHtml, 'href="/events/calendar.ics"'), 'calendar shortcode should use slugged ICS path');
|
||||||
assert_true(str_contains($sluggedCalendarHtml, 'href="/events/caldav/"'), 'calendar shortcode should use slugged CalDAV path');
|
assert_true(str_contains($sluggedCalendarHtml, 'href="/events/caldav/"'), 'calendar shortcode should use slugged CalDAV path');
|
||||||
|
|
||||||
unwrap(
|
|
||||||
request('POST', '/calendar/v1/events', [
|
|
||||||
'title' => 'Sidebar Weekday Event',
|
|
||||||
'description' => 'sidebar date label',
|
|
||||||
'start_datetime' => '2026-05-03T09:00:00+01:00',
|
|
||||||
'end_datetime' => '2026-05-03T10:00:00+01:00',
|
|
||||||
'repeat_type' => 'none',
|
|
||||||
'repeat_interval' => 1,
|
|
||||||
'repeat_range_mode' => 'none',
|
|
||||||
]),
|
|
||||||
'create sidebar weekday event'
|
|
||||||
);
|
|
||||||
$sidebarHtml = do_shortcode('[calendar_sidebar_upcoming]');
|
$sidebarHtml = do_shortcode('[calendar_sidebar_upcoming]');
|
||||||
assert_true(str_contains($sidebarHtml, '<div class="calendar-plugin-shell"'), 'sidebar shortcode should render');
|
assert_true(str_contains($sidebarHtml, '<div class="calendar-plugin-shell"'), 'sidebar shortcode should render');
|
||||||
assert_true(str_contains($sidebarHtml, 'Sunday 3 May 2026'), 'sidebar shortcode should include weekday in event date');
|
|
||||||
|
|
||||||
echo "[PASS] compatibility-layer e2e wp emulation\n";
|
echo "[PASS] compatibility-layer e2e wp emulation\n";
|
||||||
|
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
56ab7dd012a380edcc982c7c04f0f8dcb97ab0e0b4625349e2651c270949205e ./calendar-plugin.php
|
|
||||||
4e6930c79d9ce1045be6863ddd7546e19f7ef7e839d41a41014a3efb3183eaf0 ./src/bootstrap.php
|
|
||||||
1daa5861c0d10258c0d16c5c88c1a18fb3c8df7b590f7facfe7c28f678643bdb ./src/Contracts/AuthAdapterInterface.php
|
|
||||||
25cff4b0fc2ee292b53c152edd083c6af66200a25eec28f8dfce37d126a8892d ./src/Contracts/DatabaseAdapterInterface.php
|
|
||||||
4f0f4caa5ac98499854336f5b74af55ce889653f3956e5df10910f869a23fdba ./src/Contracts/HttpAdapterInterface.php
|
|
||||||
15e8f58c7360d6cd0c76c945abfeb026f8278d40b330e99b67955eb2f85f5563 ./src/Contracts/OptionsAdapterInterface.php
|
|
||||||
da068811cd923bd6cf04a209b9b4eec55fa57aeedfccaa3250ebd37b906c6d04 ./src/Domain/CalDavService.php
|
|
||||||
c8ab00f23e7cd198228734515c3ce9a2589b1ab6cb815307f3b8f7a3051e04d2 ./src/Domain/EventService.php
|
|
||||||
37b8f3077dcf9c0eb40dbcfefa7a5d8cebfe616051d827ad6ae3bb5a5fbccec7 ./src/Domain/IcsService.php
|
|
||||||
fd5377f7852b0f35550a453451d98882b8488b332d9a051dac603851c7b586d1 ./src/Domain/RecurrenceExpander.php
|
|
||||||
20ee26671fd934f36e97606cfd2ec1d5101ac8064594989bc955bf805fae2502 ./src/Domain/SettingsService.php
|
|
||||||
9956790a5d62f5798f3ec15fc507fb04f33e01fd27969db09e91a6d1b41cd33f ./src/Domain/UserService.php
|
|
||||||
5aaac066919b60461bde2e96cbfb4de66a5a28e89d2a61b78f0e2d346f23395b ./src/Infrastructure/ServiceContainer.php
|
|
||||||
e65577c707c5a66e2097faa7720170180c79a9d9df219f0e1061fdcec55be744 ./src/Infrastructure/WordPress/MigrationManager.php
|
|
||||||
8e6c95e9e1c051606e66d95cf0bcf92b2ca087bc491f32ab4921e0898cf77b81 ./src/Infrastructure/WordPress/WordPressAuthAdapter.php
|
|
||||||
68c0ca15ad2c8b6363a2578b85f8daf0d3a094e612a120a2cdd2a2bfd8fe5e3c ./src/Infrastructure/WordPress/WordPressDatabaseAdapter.php
|
|
||||||
8da85db3c1e69c2c5f01aaa2f558aa8f0323446d8af0aec5b34d4607cd4afe1b ./src/Infrastructure/WordPress/WordPressHttpAdapter.php
|
|
||||||
cf9fddcecb07af2c03ad2c0e448be12a6b45dd936efc8bc1fd46a52b4af864ea ./src/Infrastructure/WordPress/WordPressOptionsAdapter.php
|
|
||||||
e47590f2f092cfdd3c1245cd7ea392c5d91135f6ee5d468b533969f7c7c94c6b ./src/Plugin.php
|
|
||||||
893c6df62beed87a981d372c473e5012d1b5d1c254d23b39cda44ae8a08cd16c ./uninstall.php
|
|
||||||
Binary file not shown.
|
|
@ -3,7 +3,7 @@
|
||||||
* Plugin Name: Calendar Plugin
|
* Plugin Name: Calendar Plugin
|
||||||
* Plugin URI: https://chezstephens.org.uk
|
* Plugin URI: https://chezstephens.org.uk
|
||||||
* Description: Provides a single shared calendar for WordPress with public display, authenticated event editing, user approval workflow, ICS publishing, and CalDAV read/write sync. Supports recurring events, single-occurrence exceptions, admin setup and diagnostics pages, and shortcode rendering for full calendar and upcoming-events sidebar views.
|
* Description: Provides a single shared calendar for WordPress with public display, authenticated event editing, user approval workflow, ICS publishing, and CalDAV read/write sync. Supports recurring events, single-occurrence exceptions, admin setup and diagnostics pages, and shortcode rendering for full calendar and upcoming-events sidebar views.
|
||||||
* Version: 1.0.2
|
* Version: 1.0.1
|
||||||
* Requires at least: 6.0
|
* Requires at least: 6.0
|
||||||
* Requires PHP: 8.1
|
* Requires PHP: 8.1
|
||||||
* Author: Adrian Stephens (with AI assistance)
|
* Author: Adrian Stephens (with AI assistance)
|
||||||
|
|
|
||||||
|
|
@ -1019,7 +1019,7 @@ HTML
|
||||||
$end = (string) ($item['occurrence_end'] ?? '');
|
$end = (string) ($item['occurrence_end'] ?? '');
|
||||||
$startDt = $this->toSidebarDateTime($start, $sidebarTz);
|
$startDt = $this->toSidebarDateTime($start, $sidebarTz);
|
||||||
$endDt = $this->toSidebarDateTime($end, $sidebarTz);
|
$endDt = $this->toSidebarDateTime($end, $sidebarTz);
|
||||||
$dateLabel = $startDt !== null ? $startDt->format('l j F Y') : substr($start, 0, 10);
|
$dateLabel = $startDt !== null ? $startDt->format('j F Y') : substr($start, 0, 10);
|
||||||
$timeLabel = '';
|
$timeLabel = '';
|
||||||
if ($startDt !== null && $endDt !== null) {
|
if ($startDt !== null && $endDt !== null) {
|
||||||
$startTime = $startDt->format('H:i');
|
$startTime = $startDt->format('H:i');
|
||||||
|
|
@ -1422,7 +1422,7 @@ HTML
|
||||||
return [
|
return [
|
||||||
'status' => 'ok',
|
'status' => 'ok',
|
||||||
'plugin' => 'calendar-plugin',
|
'plugin' => 'calendar-plugin',
|
||||||
'version' => '1.0.2',
|
'version' => '1.0.1',
|
||||||
'db_prefix' => $this->db->getPrefix(),
|
'db_prefix' => $this->db->getPrefix(),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ CREATED_EVENT_ID=""
|
||||||
CREATED_REC_EVENT_ID=""
|
CREATED_REC_EVENT_ID=""
|
||||||
CREATED_PRIVATE_EVENT_ID=""
|
CREATED_PRIVATE_EVENT_ID=""
|
||||||
CREATED_SYNC_DELETE_EVENT_ID=""
|
CREATED_SYNC_DELETE_EVENT_ID=""
|
||||||
CREATED_SIDEBAR_EVENT_ID=""
|
|
||||||
DETECTED_URL_SLUG=""
|
DETECTED_URL_SLUG=""
|
||||||
SSH_OK=0
|
SSH_OK=0
|
||||||
|
|
||||||
|
|
@ -125,10 +124,6 @@ cleanup() {
|
||||||
curl -sS -u "${AUTH_USER}:${AUTH_PASS}" -X DELETE \
|
curl -sS -u "${AUTH_USER}:${AUTH_PASS}" -X DELETE \
|
||||||
"${BASE_URL}/wp-json/calendar/v1/events/${CREATED_SYNC_DELETE_EVENT_ID}" >/dev/null || true
|
"${BASE_URL}/wp-json/calendar/v1/events/${CREATED_SYNC_DELETE_EVENT_ID}" >/dev/null || true
|
||||||
fi
|
fi
|
||||||
if [[ -n "${CREATED_SIDEBAR_EVENT_ID}" ]]; then
|
|
||||||
curl -sS -u "${AUTH_USER}:${AUTH_PASS}" -X DELETE \
|
|
||||||
"${BASE_URL}/wp-json/calendar/v1/events/${CREATED_SIDEBAR_EVENT_ID}" >/dev/null || true
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
|
@ -348,46 +343,6 @@ PY
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
step "sidebar timezone rendering (Europe/London)"
|
|
||||||
SIDEBAR_UID="remote-sidebar-tz-$(date +%s)@calendar-plugin"
|
|
||||||
SIDEBAR_TITLE="Remote Sidebar TZ Check"
|
|
||||||
SIDEBAR_JSON=$(cat <<JSON
|
|
||||||
{"uid":"${SIDEBAR_UID}","title":"${SIDEBAR_TITLE}","description":"timezone regression","location":"Remote","category":"QA","start_datetime":"2026-04-10T09:00:00+00:00","end_datetime":"2026-04-10T10:00:00+00:00","repeat_type":"none","repeat_interval":1,"repeat_range_mode":"none"}
|
|
||||||
JSON
|
|
||||||
)
|
|
||||||
SIDEBAR_CREATE_HTTP="$(curl -sS -u "${AUTH_USER}:${AUTH_PASS}" -H 'Content-Type: application/json' \
|
|
||||||
-d "${SIDEBAR_JSON}" -o /tmp/remote_test_sidebar_create.json -w '%{http_code}' \
|
|
||||||
"${BASE_URL}/wp-json/calendar/v1/events" || true)"
|
|
||||||
if [[ "${SIDEBAR_CREATE_HTTP}" != "200" ]]; then
|
|
||||||
record_fail "sidebar timezone setup create failed (http ${SIDEBAR_CREATE_HTTP})"
|
|
||||||
else
|
|
||||||
CREATED_SIDEBAR_EVENT_ID="$(python3 - <<'PY'
|
|
||||||
import json
|
|
||||||
p=json.load(open('/tmp/remote_test_sidebar_create.json'))
|
|
||||||
print(p.get('data', {}).get('id', ''))
|
|
||||||
PY
|
|
||||||
)"
|
|
||||||
if [[ -z "${CREATED_SIDEBAR_EVENT_ID}" ]]; then
|
|
||||||
record_fail "sidebar timezone setup returned no id"
|
|
||||||
elif [[ "${SSH_OK}" != "1" ]]; then
|
|
||||||
echo "[remote-tests] WARN: SSH unavailable, skipping sidebar shortcode rendering check"
|
|
||||||
else
|
|
||||||
if ! "${SSH_PREFIX[@]}" "cd ${REMOTE_WP_PATH} && ${REMOTE_WP_CLI} eval 'echo do_shortcode(\"[calendar_sidebar_upcoming]\");' --allow-root" >/tmp/remote_test_sidebar_render.html 2>/tmp/remote_test_sidebar_render.err; then
|
|
||||||
record_fail "sidebar shortcode render check failed"
|
|
||||||
else
|
|
||||||
if ! python3 - <<'PY'
|
|
||||||
import re
|
|
||||||
html=open('/tmp/remote_test_sidebar_render.html', encoding='utf-8', errors='ignore').read()
|
|
||||||
assert 'Remote Sidebar TZ Check' in html
|
|
||||||
assert re.search(r'10(?:\.00)?(?:–|-|–)11am', html), html
|
|
||||||
PY
|
|
||||||
then
|
|
||||||
record_fail "sidebar shortcode did not render expected Europe/London time range (expected 10–11am for 09:00Z input)"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
step "caldav discovery compatibility"
|
step "caldav discovery compatibility"
|
||||||
CALDAV_ROOT_URL=""
|
CALDAV_ROOT_URL=""
|
||||||
if [[ -n "${CAL_CALDAV_PATH}" ]]; then
|
if [[ -n "${CAL_CALDAV_PATH}" ]]; then
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ Use a minimal subset:
|
||||||
### SMK-004 Public UI Rendering
|
### SMK-004 Public UI Rendering
|
||||||
- Render shortcode page with CE-002 and CE-003 present.
|
- Render shortcode page with CE-002 and CE-003 present.
|
||||||
- Assert no runtime error and event data is visible in default view.
|
- Assert no runtime error and event data is visible in default view.
|
||||||
- Sidebar shortcode (`[calendar_sidebar_upcoming]`) renders event date/time in `Europe/London` timezone semantics.
|
|
||||||
|
|
||||||
### SMK-005 ICS Endpoint
|
### SMK-005 ICS Endpoint
|
||||||
- Fetch ICS link.
|
- Fetch ICS link.
|
||||||
|
|
|
||||||
|
|
@ -60,9 +60,6 @@ Exercise the highest-value user flows across web UI, admin setup/users pages, re
|
||||||
- Open Diagnostics page:
|
- Open Diagnostics page:
|
||||||
- verify diagnostics snapshot renders.
|
- verify diagnostics snapshot renders.
|
||||||
- click `Download Diagnostics` and confirm JSON file downloads.
|
- click `Download Diagnostics` and confirm JSON file downloads.
|
||||||
- Render/check page area using `[calendar_sidebar_upcoming]`:
|
|
||||||
- confirm human-readable date/time format.
|
|
||||||
- confirm displayed times match `Europe/London` (not server UTC) for near-term timed events.
|
|
||||||
|
|
||||||
## Pass Criteria
|
## Pass Criteria
|
||||||
- No fatal errors.
|
- No fatal errors.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue