Jump to content

[SOLVED] How to add user and date to an uploaded file?


dotnetic
 Share

Recommended Posts

Hello folks,

I want to save the information which user uploaded a file and also a date in the PW admin.  I thought I could use the description field for this information, but how do I set it via a hook and how do I prevent users from editing the description?

I tried the following hook which does not set the content of the description field (seems to be not a property of the InputfieldFile, but an individual field).

 /**
   * if this is a fachbereich or abteilung add a hook to prevent file deletion
   * @param HookEvent $event
   */
  public function hookPageFile(HookEvent $event)
  {
//    if ($this->user->isSuperuser() || $this->user->hasRole('restricted-admin')) {
//      return;
//    }
    $page = $event->object->getPage();
    // Only use on pages with the raum template
    if (($page->template == 'fachbereich' || $page->template == 'abteilung') && !$page->isTrash()) {

      $this->addHookAfter('InputfieldFile::processInputFile', function(HookEvent $event) {
        // Get the object the event occurred on, if needed
        $InputfieldFile = $event->object;
        $InputfieldFile->description="no description";
        bd($InputfieldFile, "processInputFile");
      });

      $this->addHookBefore('InputfieldFile::processInputDeleteFile', $this, 'preventFileDelete');
    }
  }

The hook should also be only executed on pages with a specific template, so that's why I use 

    $this->addHookBefore('ProcessPageEdit::buildForm', $this, 'hookPageFile');

Is this even possible, or should I take a completely different route? Maybe save the inputfield_id, filename and created_user in a separate database table? But this would complicate things, because on the output side I have to query the custom database instead of using just the description field.

Maybe I can use the just added custom fields for files/imags in ProcessWire 3.0.142 for this? But how do I set the values in the admin for them and prevent changing them by the user? Think I have to test this out.

EDIT: Found a solution with the help of the nice guys in this forum. You can find it here: https://processwire.com/talk/topic/22411-how-to-add-user-and-date-to-an-uploaded-file-help-urgently-needed/?do=findComment&comment=192363

 

Edited by Jens Martsch - dotnetic
Solved
  • Like 1
Link to comment
Share on other sites

Datetime of files are already saved automatically by the API, but without created/modified infos about the user.

Maybe using a hook and set / modify page meta would work?

I haven't looked into the brandnew PW dev branch and the new custom fields for files. This would be the most straightforward way - if you could easily protect those custom (sub-) fields in the admin (not viewable, not editable - same way you can use any regular field). But even then you would need a hook (maybe this one?)

Link to comment
Share on other sites

Hi Jens, what Dragan said, if you can switch & test to PW 3.0.142 with the new implemented images subfields, that would be simple to setup and protect for usernames / ids and modified or uploaded timestamps. But you need to test it in a dev environment first, as it is "brandnew".

I believe the best hook for all file and image related things on upload  is >before "InputfieldFile::fileAdded" < (https://processwire.com/talk/topic/22252-admin-hook-image-upload-watermark-pim/?tab=comments#comment-190948

 

Link to comment
Share on other sites

On 10/12/2019 at 5:20 PM, Jens Martsch - dotnetic said:

But this would complicate things, because on the output side I have to query the custom database instead of using just the description field.

Why?

What is your exact goal? Maybe a simple file log would be enough?

user foo added image foo-img-1.jpg
user foo added image foo-img-2.jpg
user bar added image bar-img-3.jpg

This could be stored in /site/assets/files/123 and showed on the page edit screen when editing page 123.

Even better would be a module that logs serveral kinds of admin activity. I'd need such a module myself - so if that is what you are trying to achieve let's see if we can put something together that is reusable for everybody ? 

  • Like 1
Link to comment
Share on other sites

My goal is to show which user uploaded a file and when in the PW admin when editing a page.

Custom fields for files/images in ProcessWire 3.0.142 seem to be a solution for this, but I have to test them a little bit more in my environment, but they seem to work fine in a fresh install.

 

  • Like 1
Link to comment
Share on other sites

@bernhard Regarding a log module: I wrote a hook that logs all deletion of pages into a log file. This is very easy to accomplish. Depending on what you want to log, this can be a big task or a small one. Are you aware of MarkupActivityLog, which logs changes to a page? But maybe that's not what you want, as you talked about admin (superuser) related activities.

  • Like 1
Link to comment
Share on other sites

46 minutes ago, Jens Martsch - dotnetic said:

My goal is to show which user uploaded a file and when in the PW admin when editing a page.

That can mean lots of different things... Show it directly beneath the image, show a filterable list of actions who uploaded which image to what page etc.; Depending on the exact goal the best solution can be totally different from one situation to the other.

Link to comment
Share on other sites

1 hour ago, bernhard said:

Show it directly beneath the image

The best way to show the information in my case would be like in the following screenshot.

image.thumb.png.f98a01170ae2b8c36665055e99286aa5.png

Maybe this information could be saved in the file metadata, but how would I do that? Then I would hook into renderItem of InputfieldFile and change the displayed information.

What do you guys think, is this even worth to be implemented into the core and one could choose if this information is shown or not? An option like "Show metadata on files and images".

I also want to get the last file a specific user uploaded. So if multiple users uploaded files to one (same) page, I want to get the last file that user X has uploaded.

Link to comment
Share on other sites

That's not a recommendation and a little offtopic, but that sounds a little bit like what I'm always doing with grids (be it RockGrid or RockTabulator). I'm storing everything as pages and I'm listing everything in a grid. That has the benefit of being extremely flexible and extremely user friendly. Users can filter, sort, export, etc and you can colorize and add icons to everything. And (thanks to PW) you can add as many and as custom fields as you want (uploaded by, last edited at etc).

For example I'm handling invoices, each invoice is a pw-page and has several fields (date, pdf, date_due, date_sent, etc). This might theoretically also be possible now that we have the new custom image fields, but as ryan mentioned there might be some situations where things will not work). And pages will work ? 

I'm then creating a Tabulator to list all invoices on a grid (usually that's a lot better for users than finding their way through the pagetree). That's a simple RockFinder2->find().

On a client's edit screen you can even re-use this grid and show the same information but show only invoices that belong to that client. That's a simple $selector['client'] => $client in the grid's data setup file.

Using repeaters or file fields is usually a lot more complicated in the long run. IMHO they are great for websites or website content (like showing bullet points of one page or showing a handful of downloadable files on a blog post), but as soon as you are doing some kind of database application it's best to avoid them as much as possible and stick to the "pages and page relations paradigm" using regular pages and referencing them via page reference fields.

--

If you really want to show that information directly on the file entry I think that's nothing that the core needs. Just hook in the field markup and show that information. IMHO it does not really matter where you store that info. It could be a custom db table, a hidden textarea storing a json string linking filenames to additional data. Or it could be the new file fields (which - I guess - technically would be quite similar to a solution that uses custom pages + fields and RockTabulator). Maybe you could even use https://processwire.com/api/ref/page/meta/ instead of a hidden textarea + json. Never tried it though ? 

Sounds like $page->meta + hook could be worth a try ? 

  • Like 2
Link to comment
Share on other sites

Thanks for your detailed answer, but I can not change the current behavior how or where files are added, because they are already there as pagefiles in thousands of pages.

For the next project I think the recently added custom fields for pagefiles are the perfect solution, or the way you described with pages.

Using page->meta would be not a good solution in my opinion, because it stores information about the file (uploaded by user) apart from the file itself. I think the best way would be to store the information who uploaded the file into the pagefiles metadata. Now I have to figure out, how to do that.

Link to comment
Share on other sites

5 minutes ago, Jens Martsch - dotnetic said:

Using page->meta would be not a good solution in my opinion, because it stores information about the file (uploaded by user) apart from the file itself.

I don't see a problem and that's exactly how ProcessWire itself does it...

5QF4l2H.png

  • Like 1
Link to comment
Share on other sites

Here is my working solution, which looks not exactly as in my example screenshot, because for that I had to use a str_replace. So I added the information below the file.

image.thumb.png.18cc45dee5858861f0be8296acd51457.png

The process is the following:
User uploads file. The URL of the file and my custom information string are saved via $page->meta.
Then before rendering the PageFile item the URL in the $page->meta is looked up and the custom information appended to the markup.
I do this only on pages with a specific template.

Here is the code:

$this->addHookBefore("InputfieldFile::fileAdded", function ($event) {
            $pagefile = $event->arguments[0];
            //$pagefile->description = "Hochgeladen von {$this->user->name} am " . date("Y-m-d H:i:s"); // not used, because description can be altered by users
            if ($event->object->data["hasPage"]) {
                $page = $event->object->data["hasPage"];
                if ($page->template->name == "abteilung" || $page->template->name == "fachbereich") {
                    $page->meta($pagefile->url, "Hochgeladen von {$this->user->name} am " . date("m.d.Y H:i:s"));
                }
            }
        });

        $this->addHookAfter('InputfieldFile::renderItem', function ($event) {
            $url = $event->arguments[0]["url"];
            $page = $event->object->data["hasPage"];
            if ($page->template->name == "abteilung" || $page->template->name == "fachbereich") {
                $event->return .= "<p>{$page->meta($url)}</p>";
            }
        });

 

  • Like 1
Link to comment
Share on other sites

Looks like a good use for $page->meta ? If you stored the data raw (userid + timestamp) and created the german string + date on render you'd be safe for future updates (multilanguage for example) and you'd be able to change the date time format instantly for all files.

  • Like 2
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...