Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 04/02/2024 in all areas

  1. I've added a new sub-project to my PWGeeks site that turns the ephemeral activities shown in the PW forum's Online Users & All Activity pages into a live-updating, unified, timeline of events - both what users are replying to - and what they are viewing. Whilst it is not built with Processwire, it is related and was an interesting little project to build. I thought I'd post about it here in case it's of use to anyone else. You can find it here: https://activity.pwgeeks.com/ Clicking on a username drills down into their activity, but more on that later. Unlike the usual All Activity view on the forum, this integrates consumption activities (viewing stuff) with production activities (posting/replying.) Unfortunately, due to a limitation on what the forum lets non-logged in readers see, reactions to posts cannot be tracked at this time. I initially thought this might be useful just to make the ephemeral viewing activity more obvious, but I'm now hoping that it can be turned into a tool to more easily help forum moderators deal with spammers (new joiners who quickly start posting). But that's yet to be proven. If you don't wish your read/write activities to be traceable, you can login to the forum in anonymous mode. Architecture The architecture is split into a long-running ReactPHP Watcher Service, and the Index Generator code which creates the page you just viewed with the help of Caddy, PHP8.2 and PHP-FPM. It all runs on a cheap Contabo VPS. Both Caddy and the watcher process are defined as systemd services that are automatically restarted if they fail, or the box is rebooted. Pusher is used to provide a Pub-Sub channel for immediate communication of changes found by the watcher service to anyone who is viewing the index pages - allowing the index to be updated as forum activity is detected by the watcher. Pusher takes care of any fan-out needed between the Watcher Service publishing the events, and any browsers subscribed, via Pusher-JS. I used Pusher's free tier and created an "application" to get my channel and the needed credentials, which went in a .env file. I also turned on subscription counting on the channel within Pusher's dashboard to allow simple console logging of the number of clients connected to the channel at any one time. All detected activity is also stored in a local SQLite DB which allows the Index Generator to build the initial table of activity shown in your browser. Once the page is loaded, JS events take over and continue populating the table in (almost) real time as they come in from Pusher. The Watcher Service ReactPHP is used to create a long running server process, in PHP, that has run for more than 2 months at a time with rock-solid (no, that's not a bernhard module) memory use at 10MB once all the user data is loaded from the DB. I am sure this process would have run indefinitely, but I recently restarted the service to add detection of write-activities on the forum. The major Composer packages used are pusher/pusher-php-server (to publish to my app's event channel) vlucas/phpdotenv (to read the pusher credentials from an .env file) react/event-loop (to run the PHP app indefinitely) fabprot/goutte (for scraping the 2 forum pages) symfony/console (for CLI output formatting and logging) I would probably choose a different scraping library if I were to do this again, but goutte works just fine for now. The watcher only uses two public forum pages; the Online Users page, with the logged in filter applied, and the All Activity page. It is worth noting that the service has no log-in details, so sees these pages as a logged-out visitor to the forums would - which means significantly less information is available to it than to you if you view those pages when you are logged in to the forum. All Activities Page Differences When logged in, the All Activities page shows user reactions to posts (2 below). These are not available to guests, so cannot be tracked by the Watcher Service. If you have purchased Pro modules and have access to some of the VIP forums, then new posts or replies to posts in those forums are also shown (1) Guests have no access to either of these - so VIP forum activities are not tracked. The Watcher Service does not have any login credentials, so this is the view it sees... All activities listed on this page have a UTC timestamp in their HTML attributes that can be used to record the actual time of Joins, New topics and replies being posted. I don't bother recording any "user started following..." activities. Online Users (logged in) You might not be aware of this page on the forum, but it's how the Watcher Service can tell who's viewing forums & posts, creating new topics, or using the personal messaging service. If you have never visited this page on the forum, you want (1) browse, 2(Online Users) and then use the Filter-By dropdown to view logged-in users. The activities listed (3) do not have a timestamp in the HTML - so the watcher limits itself to anything that happened "Just Now" that has not yet been recorded for that user and uses the server's time() to record the event as having occurred. When users view a VIP forum or post, or visit the All Activity page, the user list page does not show what the user is viewing - it just shows their activity as a blank string (See netcarver's activity in the above screenshot.) Other Limitations The main loop of the service runs several times a minute and scrapes and de-duplicates activities from the forum. Any activity that happens on the forum between these samples are undetectable. So, if you visit a forum and then quickly click into a topic, and then back out, your activity will not be traceable. The Event Loop Using ReactPHP is conceptually quite simple, but there are a few things to keep note of. Here's the basics of the Watcher Service... <?php declare(strict_types=1); namespace Netcarver\ForumActivityMonitor; require_once 'vendor/autoload.php'; use React\EventLoop\Factory; ... use Pusher\Pusher; use Dotenv\Dotenv; require_once __DIR__ . '/.format.php'; // output formatting helpers require_once __DIR__ . '/.storage.php'; // storage class $dotenv = Dotenv::createImmutable(__DIR__); $dotenv->load(); // Create pusher publication connection $pusher = new Pusher( $_ENV['PUSHER_KEY'], ... ); $sample_period_seconds = 20; $started_ts = time(); $output = new ConsoleOutput(); $output->write("\n>>> ProcessWire Forum Activity Monitor (sampling every $sample_period_seconds seconds) <<<\n\n"); // Open the local SQLite DB for storage layer... $db = new \PDO('sqlite:path/to/database.sqlite'); $storage = new Storage($db); $loop = Factory::create(); $loop->addPeriodicTimer(1, function () use (&$storage, $started_ts, $sample_period_seconds, &$pusher, &$output) { $now = time(); $can_access_pw_forum = ($now % $sample_period_seconds === 0); $elapsed_time_seconds = $now - $started_ts; showStatusLine($output, $can_access_pw_forum, $storage->userCount(), $elapsed_time_seconds); if ($can_access_pw_forum) { $client = new Client(); try { // Scrape, dedupe & store events ... // publish events via pusher... if (!empty($event_timeline)) { ksort($event_timeline); $table = new Table($output); $table->setHeaders(['#', 'Time', 'UID', 'Username', 'Activity']); $mem_use = memory_get_usage(true); $runtime_str = formatElapsedTime($elapsed_time_seconds); $pusher_events = []; foreach ($event_timeline as $events_at_time) { foreach ($events_at_time as $event) { $uid = $event['uid']; $user_activity_count = $storage->getUserActivityCount($uid); $table->addRow([$user_activity_count, $event['time'], $uid, $event['user'], $event['activity']]); $pusher_events[$event['time']][] = [ 'uid' => $uid, 'url' => $event['url'], 'user' => $event['user'], 'act' => $event['activity'], 'mem' => $mem_use, 'uptime' => $runtime_str, 'type' => $event['type'], ]; } } $pusher->trigger('activities', 'update', $pusher_events); $table->render(); $output->write("\n"); } } catch (\Throwable $e) { $output->write("\nCaught Throwable: ".$e->getMessage()."\n\n"); } } }); $loop->run(); Note that Pusher, the storage instance, and the console are all passed into the loop closure by reference so state can be maintained between each scheduled call to the loop function. The loop closure uses a try {} catch (\Throwable) {} block to ensure it keeps running without systemd having to restart it in case of a PHP error. The catch block does occasionally run - so far if DNS resolution fails when scraping the forum. I've omitted the scraper and de-dupe code from the above as they are still a work in progress, but they populate an $event_timeline array if anything new is detected. The unified array of events (if any) is published via Pusher and each entry includes information about the Service uptime and memory usage. The Index page simply console logs this meta-data from the first event in the array of activities it receives, so you can use your browser's console to track these (along with the number of subscribers to the channel)... I made the event loop run every second, even if it's not time to sample the forum, so the CLI output can be updated regularly. This was especially useful when initially running the Watcher from the command line and I could probably drop the status updates now things are run via Systemd. Running from the CLI on the server, or tailing the log file, gives a nicely formatted table of events as they occur thanks to Symfony's console library and table helper. Systemd Integration To allow automatic restart of the watcher when the VPS is restarted, I added this service definition file to /etc/systemd/system/forumwatch.service that runs the watcher as an unprivilaged user... [Unit] Description=ReactPHP Processwire Forum Watcher [Service] ExecStart=/usr/bin/php8.2 /home/pwfw/activity.pwgeeks.com/watcher/react.php WorkingDirectory=/home/pwfw/activity.pwgeeks.com/watcher/ StandardOutput=file:/var/log/pwforumwatch.log StandardError=file:/var/log/pwforumwatch.log Restart=always User=pwfw Group=pwfw [Install] WantedBy=multi-user.target A quick sudo sytemctl enable forumwatch.service && sudo systemctl start forumwatch.service is then all that's needed to get things running. As the output is logged to /var/log/pwforumwatch.log, I also gave it a logrotate.conf file to keep things under control. The Index Generator This is a single index.php file that takes care of reading the most recent user activities from the SQLite DB and generating the table of events from it for that point in time. JS is included (pusher-js) that subscribes to the application's activity channel. Pusher's free tier allows up to 100 simultaneous connections to the event activity channel, and you can see how many users are connected via your browser's console. NB: The following feature is now behind a basic auth login. If you click on a user's name, you'll reload the page with a filter that lists only that user's activities. Here are Bernhard's as he has posted recently as I write this up. Click on the User's name or avatar (1) to be taken to their page on the forum, or click on the "Everyone" or PW logo (2) to be taken back to the all-inclusive index. Trying It Out I recommend opening the activity tracker in one browser on one side of your screen, then opening the Forum (and logging in) in another browser on the other side. As you (and anyone else) visits pages on the forum, you should see things update in the tracker. Also open up the console on the tracker page to see uptime/memory and viewing user count data as they come in. If you read this far, thank you for your time, and I hope this was of some interest or use to you.
    4 points
  2. The RockFrontend site profile for ProcessWire offers a unique combination of benefits by integrating UIKit and TailwindCSS, making it an appealing choice for developers looking for both robust UI components and extensive customization capabilities. Here are some key advantages: Rich UI Components from UIKit UIKit is known for its comprehensive collection of high-quality, ready-to-use UI components. This integration in the RockFrontend site profile allows developers to quickly implement complex components like modals, accordions, and sliders that are visually appealing and functionally robust. Flexibility and Customization with TailwindCSS TailwindCSS is a utility-first CSS framework that provides high granularity in styling elements. It allows developers to build custom designs without stepping out of the framework’s constraints. This can significantly speed up the development process, as it eliminates the need to write custom CSS from scratch. Setup Setup is as simple as these 3 steps: Download the profile Install ProcessWire and choose this profile Follow the instructions on the welcome screen Github: https://github.com/baumrock/site-rockfrontend Modules Directory: https://processwire.com/modules/site-rock-frontend/
    2 points
  3. Hi guys. Check out my latest project Casa Douro Guesthouses. As the name implies, Casa Douro offers a few guesthouses in historic Porto and on the Douro Region. They came to us looking for a well built website that would fit their marketing efforts and grab direct reservations, instead of relying only on Booking.com and Airbnb. Since their channel manager (CM) software only offers a cookie-cutter website and no API, ours does all the presentation and jumps straight to the booking system when the user decides to make a reservation. As usual on my sites, pages are built using a blocks system (Profields Repeater Matrix), allowing the admin to change things up a little bit between the different units. Plus the usual WireMailSMTP, SEOMestro, and Rockfrontend because I love using Latte templates. The frontend is a mix of Tailwind + SCSS on more complicated components, and JS over Vite which allows me to keep it as vanilla as possible. We already have plans for new sections, and maybe upgrade the booking system in the future.
    2 points
  4. From the newsletter: RockFrontend ❀️ HTMX And all I can say so far: YES!!!
    2 points
  5. Just a note to say that I've added a new Page Meta section to the Request Info panel. This displays all meta entries for the page, along with links to open the entries for editing directly in Adminer. Speaking of Adminer - it was recently updated to AdminerEvo and I changed the way links from Tracy to open Adminer work - they now open the bar panel version which I believe is a much nicer experience than the standalone Adminer page. I also added links to edit the values of all fields within the Page Edit interface. If the field has multiple values, it will open Adminer showing all entries instead. This is of course optional, so you can visit the Adminer settings (now merged into Tracy's settings) to turn this off if you prefer. Please note that when you first upgrade, you will likely need to do a modules > refresh to get Adminer to load properly the first time.
    2 points
  6. Likewise. It's certainly not a deal-breaker, and the showIf fix is a big step forward for my needs. ?
    2 points
  7. @iank I'll double check on my end, I may have not tested thoroughly enough, or got inconsistent results. Not sure about yours, but in my case the most important component was the showIf since it is the primary method of indicating the action a user should take and important way to keep the UI tidy. If you continue configuring your fields to use requireIf then any update to RPB would mean those field settings will be respected. So hopefully it doesn't slow your development too much.
    2 points
  8. @bernhard, showIf conditions are now working as expected. These are working in all three edit modes: Full page edit, block "edit in new window" and front-end block edit with Alfred. However, This is not working for me when editing a block in full page edit mode. If a requiredIf condition is met, then none of the block's changes are persisted. When editing a block via "edit in new window" or front-end with Alfred, the requiredIf conditions work and the changes are saved. Sorry to be a pain - I think we're almost there, but I can't for the life of me figure out why this is happening only in the full page edit scenario. I can create a screencast demonstrating the issue if that would be helpful. Thx, Ian.
    2 points
  9. Hi again @adrian wow, faster than the light speed, just downloaded the last release and, yes, it works really well, thanks so much!!! and, you know, don't be confused by my response, it's just that i thought you may have something else to do than reacting that fast, i'm stunned and at the same time it's so pw like ? i should be used to it thank you very much again and have a nice day, mine is even nicer, saved some time thanks to you ?
    2 points
  10. Thank you for the site profile and especially the blog post and extensive comments throughout the code. It's extremely helpful for overall architecture examples, which is something hard to find by just reading documentation or searching forum, because recommended practices have changed over the years. Especially love learning how you do things in the admin side for customizing the page edit screens, etc.
    2 points
  11. I'm thrilled to announce the official release of RockPageBuilder, the game-changing tool that's set to transform your web development journey (at least ChatGPT says so ??)! With its brand new drag-and-drop interface RockPageBuilder is your secret weapon for creating outstanding ProcessWire-based websites. Get a taste of the future of web development by visiting the demo page at https://pagebuilder.baumrock.com/ and exploring the RockPageBuilder documentation at https://www.baumrock.com/en/processwire/modules/rockpagebuilder/docs/ Don't miss out on this exciting opportunity to elevate your web development game. Get ready to rock with RockPageBuilder! ??️ https://www.baumrock.com/rockpagebuilder/ Here is a quick demo video: And here is how to install it from scratch in under 5 minutes: Some showcase projects are already in the pipeline ? So be sure to subscribe to https://processwire.rocks/ or to https://www.baumrock.com/rock-monthly/ Have a great weekend!
    1 point
  12. The invoices application site profile that I uploaded last week now has a companion blog post: https://processwire.com/blog/posts/invoices-site-profile/ Thanks for reading and have a great weekend!
    1 point
  13. Thanks @bernhard, looks like this is now fixed. I'll mark this topic as solved.
    1 point
  14. Hi @bernhard ReactPHP has been very solid for long running server processes in my experience. There's also Framework-X which is a nice layer on top, though I haven't used it much. And FrankenPHP - which I have never used, though it might allow long-running async stuff as well. Sorry to make you feel tracked, I guess things like this that simply snapshot publicly available ephemeral info and turn it into a timeline are somewhat borderline. If people are worried about this I'm happy to take this service down, or put it behind basic auth so only the forum mods have access. Basically, I want to get to the point where I can detect Join Events followed by new topic creation prior to it being published in order to get an early warning of possible spammers. This tool might be able to do that (time will tell.)
    1 point
  15. I am confused by your response - you can write a module to do it if you want, but the problem you had with those errors should now be fixed, so you should be able to use this module now.
    1 point
  16. Great so see someone else working with ReactPHP as I'm also evaluating it for a new Project ? Thx for sharing! Though I feel a little tracked now ?
    1 point
  17. Hi, funny little problem; if i allow the users to modify the export settings and, for example just want to export the children IDs and titles, il doesn't export a csv at all but tables containing php errors --- Notice: Trying to get property 'type' of non-object in D:\wamp\www\terrapixa\epifnew\site\assets\cache\FileCompiler\site\modules\BatchChildEditor\ProcessChildrenCsvExport.module.php on line 248 Notice: Trying to get property 'type' of non-object in D:\wamp\www\terrapixa\epifnew\site\assets\cache\FileCompiler\site\modules\BatchChildEditor\ProcessChildrenCsvExport.module.php on line 254 --- same thing if i just try to add the ids to the original field list funny enough, everything works like a charm if i delele this user permission, nice csv as the output but, too bad, without the children ids ? have a nice day ---
    1 point
  18. Hello @bernhard Since yesterday I am unable to login to download the latest release. Endless loading... (different browsers)
    1 point
  19. @ottogal - I really don't know - it's not likely an issue with the perms set in config.php, but perhaps the module folders themselves. It might even be the "owner" being off, rather than the permissions, especially if you FTP'd things across initially. Anyway sounds like you have it sorted for now, so let's not worry too much about it.
    1 point
  20. Thx @iank and @Klenkes please grab version 5.3.2 which has the fix provided by @iank - thank you very much!!! ? PS: Please mark the topic as [solved] again, thx ?
    1 point
  21. Hey, I just came across this thread because I ran into this issue. It turns out if you feed the configuration a single spaced empty string it will not wrap the WYSIWYG content in the paragraph tags. And for whatever reason, span was causing my system to become unresponsive. I didn't see this mentioned here or in the TinyMCE forum so figured I'd share here incase it helps save someone some time. Go to: Modules > Configure > InputfieldTinyMCE scroll down to Default setting overrides... Hack the Planet!
    1 point
  22. Theo_gg had a really solid take that I believe is applicable to many disciplines being threatened by the AI incursion. If you need an excuse to stop coding, Devin is more than willing to provide you with that excuse. If you don't want to stop coding, Devin will absolutely not take away the need for you to provide innovative and custom solutions. AGI may be more of a threat, but still - we are at a point where AI is able to teach and perform things for people that someone already knows how to do. And you can get really far with this, but it is not the endless threat. Think about how valuable it will be as part of the singularity to be exposed to every post on Twitter. There's a lot more junk than AI knows what to do with at this time. Once that changes, life is going to get interesting. It will be different. I don't think people will be interested in having their freedom curbed because a machine is better at determining their motives and endgame than they are. I say this as someone who has worked in business intelligence, where this comic ABSOLUTELY indicates how interested people are in giving authority to numbers and facts:
    1 point
  23. If you want a solid solution that has seen several years of development and is tailored exactly towards that use case have a look at RockPageBuilder: It will not only make your life as a developer easier, it will also tremendously improve the editing experience for your clients. Try it out yourself at https://pagebuilder.baumrock.com
    1 point
  24. PAGEGRID 2 is out now! ? The new version contains several bug fixes and adds exciting new features. It's also more flexible and easier to use. Check out the new website ? and click the edit button ✏️ to see for yourself. With this update, PAGEGRID becomes a very flexible no-code editor that still gives developers the power and control they need. Easily modify existing block templates or create your own with your favorite code editor and ProcessWire's powerful API. Use PAGEGRID to build whole websites, connect PAGEGRID to regular ProcessWire templates/pages or use PAGEGRID only as a "body" field. PAGEGRID 2 uses as many native features from ProcessWire as possible (everything is a page). NEW Reusable Symbols Turn nav bars, footers, or any combination of items into symbols that you can reuse wherever you need them. (Symbols are pages) Animations Add powerful multi-step CSS animations with a few clicks. Use interactions like scroll, mouseover, inview, loading or click to trigger them. Reuse them throughout your website. (Animations are pages) Blueprints Blueprints can be used to automatically populate empty pages with a predefined layout. They are useful if you want website editors to start from a base design when they create new pages. (Blueprints are pages) DOM Navigator The dom navigator makes it possible to select any markup on the page through PAGEGRID's style panel. It gives you full control over your site's appearance. Style regular templates Make CSS edits to any template inside processwire just by adding the PAGEGRID field to it (works with any markup). VW and VH units Almost all style inputs now support PX, %, VH and WV units. Updated Google Fonts The fonts list has been updated to include the latest fonts and material icons. Datalist Block (PageGridBlocks module) The new datalist block renders a link list of pages that you can define. It can render a title, thumbnail, video, or text per page. This can be useful for rendering a grid of your latest portfolio projects, news, or a list of articles. iFrame Block (PageGridBlocks module) The new iFrame block uses layziframe to layziload any iFrame when you click a placeholder. You can upload a custom placeholder or, for YouTube/Vimeo, the placeholder can be loaded automatically and saved to the database (to comply with the EU General Data Protection Regulation). This is great for embedding external services such as YouTube, Vimeo, Spotify, Soundcloud, or others to your site. –––––––––––––––––––––––––– How to update from version 1: Please make sure you run the latest ProcessWire version before updating. I would also recommend to make a database backup for existsing websites before the update (just to be save). Then simply update the FieldtypePageGrid and PageGridBlocks modules.
    1 point
Γ—
Γ—
  • Create New...