We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 1331
    • 129 Posts
    I have a client who is creating a site where users would become member. Based on the membership they choose, they'll be able to access fresher and fresher information. With the highest level being up-to-minute postings.

    I have already gotten a conditional getResources that publishes a list (based on these levels) and only hows items that are older than 60 and 90 days, etc.

    But that does not handle the ACLs for said postings. If an unauthorized user happens across a link to a post from today, it'll still display for him.

    I have the resource groups all set up, but we don't want to have to check boxes every day as they age. I would like to write a script that checks the entire resource tree and then ticks the appropriate Resource group once a document crosses the threshold for that group.

    In other words, when a posting becomes more than 60-days old, I want it to run a cron at 12AM that will go ahead and put it in the "older than 60 days" resource group. And if we change the 'publishedon' date, the cron job would see that and uncheck 60 and put it in the other group for more recent stuff.
      • 38290
      • 712 Posts
      I have done similar things, and found RegenCache to be a great boilerplate for any sort of CRON task that works with Resources.
      http://devries.jp/blog/2013/03/23/cash-in-big-with-modx-cacheing/#regencache

      What is below is untested, but based on RegenCache and some code I've used to add/remove resources from Resource Groups.

      <?php
      $tstart = microtime(true);
      set_time_limit(0);
      
      require 'config.core.php';
      require MODX_CORE_PATH . 'model/modx/modx.class.php';
      
      $modx = modX::getInstance();
      
      $modx->initialize('mgr');
      
      $modx->setLogLevel(modX::LOG_LEVEL_INFO);
      $modx->setLogTarget('ECHO');
      
      $modx->log(modX::LOG_LEVEL_INFO, "Regenerating MODX Cache");
      try {
          $iterator = $modx->getIterator('modContext', array('key:!=' => 'mgr'));
          foreach ($iterator as $context) {
              if ($modx->switchContext($context->get('key'))) {
                  $modx->setLogLevel(modX::LOG_LEVEL_INFO);
                  $modx->setLogTarget('ECHO');
                  $modx->log(modX::LOG_LEVEL_INFO, "Processing Resources in Context {$context->get('key')}");
                  $map = array_reverse($modx->context->aliasMap, true);
                  $modx->log(modX::LOG_LEVEL_INFO, "Processing aliasMap: " . print_r($map, true));
      
                  foreach ($map as $uri => $id) {
                      $resource = $modx->getObject('modResource', $id);
      				$pubon = $resource->get('publishedon');
      				$now = time();
      				$day = 60 * 60 * 24;
      				if($now - $pubon > $day * 60) { // its older than 60 days
      					// leave every other group
      					$rgrs = $modx->getCollection('modResourceGroupResource', array('document'=>$id));
      					$groups = array();
      					foreach($rgrs as $rgr) {
      					    $gid = $rgr->get('document_group');
      						$resource->leaveGroup($gid);
      					}
      					
      					// join the appropriate group
      					$query = $modx->newQuery('modResourceGroup');
      					$query->where(array('name' => '60DaysGroup'));
      					$group = $modx->getObject('modResourceGroup',$query);
      					$joinGroup = $group->get('id');
      					$resource->joinGroup($joinGroup);
      				}
                  }
      
              } else {
                  $modx->log(modX::LOG_LEVEL_ERROR, "AutoGroup: Could not switchContext({$context->get('key')})");
              }
          }
      } catch (Exception $e) {
          $tend = microtime(true);
          $totalTime= sprintf("%2.4f seconds", ($tend - $tstart));
          $modx->log(modX::LOG_LEVEL_ERROR, "AutoGroup failed in {$totalTime}: {$e->getMessage()}");
      }
      
      $tend = microtime(true);
      $totalTime= sprintf("%2.4f seconds", ($tend - $tstart));
      
      $modx->log(modX::LOG_LEVEL_INFO, "AutoGroup executed in {$totalTime}");
        jpdevries
        • 3749
        • 24,544 Posts
        It sounds like that would work, but I think I'd use a much simpler method and more reliable method. With your method, new pages would be available to everyone until the cron job runs unless you remember to put them in the appropriate resource group or create a plugin to do it.

        I'm assuming that there is a user group for each level, I'll call the User Groups "Zero", "Sixty", and "Ninety".

        I'd put this snippet tag in the template(s) for all pages you want to protect:

        [[!AgeCheck]]


        with code like this:

        <?php
        /* AgeCheck snippet */
        $currentUser = $modx->user;
        
        /* make sure user is logged in */
        if ($currentUser->hasSessionContext('web')) {
            /* get current timestamp */
            $now = time();
            /* get the page's birth date as a timestamp
               (we could use 'publishedon' or 'editedon' here) */
            $pageBirthday = strtotime($modx->resource->get('createdon'));
        
            /* Get page age in days */
        
            /* rounds up to nearest day */
            $pageAge = ceil(($now - $pageBirthday) / 86400);
        
            /* rounds down to nearest day */
            // $pageAge = floor(($now - $pageBirthday) / 86400);
        
            /* Check the user's User Group */
            if ($currentUser->isMember('Zero')){
                return '';
            }
        
            if ($currentUser->isMember('Sixty') && ($pageAge >= 60)) {
                return '';
            }
        
            if ($currentUser->isMember('Ninety') && ($pageAge >= 90)) {
                return '';
            }
        }
        /* User fails all tests, cannot see the current page */
                
        return 'Sorry, you are not authorized to see this page';
        
        // or 
                
        $url = 'http://full/url/of/sorry/upgrade-your-subscription/page'; 
        $modx->sendRedirect($url);


        The return ''; lines essentially do nothing and the user sees the page.

        [ed. note: BobRay last edited this post 13 years, 2 months ago.]
          Did I help you? Buy me a beer
          Get my Book: MODX:The Official Guide
          MODX info for everyone: http://bobsguides.com/modx.html
          My MODX Extras
          Bob's Guides is now hosted at A2 MODX Hosting
          • 38290
          • 712 Posts
          Bob's more manual ACL via a snippet method could make more sense if it gets you what you need. That way you aren't managing creating and removing users from user groups as well as updating Resource Group permissions.

          If it turns out you need to do so, good news is xPDO can do it! For example, you can use and abuse runProcessor like so to do something like add Resource Group permissions to a User Group:
          // add created Resource Group access to created User Group for vendor context
          $response = $modx->runProcessor('security/access/usergroup/resourcegroup/create',array(
             'action' => 'create',
             'target' => $resourceGroup->get('id'),
             'context_key' => $context,
             'authority' => '6999',
             'principal' => $userGroup->get('id'),
             'policy' => '4'
          ));
          if ($response->isError()) {
              echo $response->getMessage();
          }


          For my uses, I would perform a task in the manager, inspect the XHR request with Developer Tools, and then replicate the action using runProcessor in my scripts.
            jpdevries
            • 4172
            • 5,888 Posts
            a simpler way could be just to filter the getResources by publishedon, depending on the usergroup, the user is in.

            &where=`{"publishedon:<=":"[[!getGroupEndDate]]"}`


            untested snippet-code:
            $groupdays = array(
            'group_0'=>'0',
            'group_30'=>'30',
            'group_60'=>'60',
            'group_90'=>'90',
            );
            
            foreach ($groupdays as $group=>$days){
                if ($modx->user->isMember($group)){
                    return  strftime('%Y-%m-%d %H:%M:%S',time() - ($days * 24 * 60 * 60));
                }
            }
            
            return  strftime('%Y-%m-%d %H:%M:%S',time() - (120 * 24 * 60 * 60));//If user isn't in any of this groups
            


            [ed. note: Bruno17 last edited this post 13 years, 2 months ago.]
              -------------------------------

              you can buy me a beer, if you like MIGX

              http://webcmsolutions.de/migx.html

              Thanks!
              • 3749
              • 24,544 Posts
              Bruno17's method points up a down side to my method. With my method, there's no easy way to hide pages in the menu that the user is not authorized to see. On the other hand, showing the pages gives the users an incentive to upgrade and lets you forward them to a page where they can upgrade, which might improve subscription rates.
                Did I help you? Buy me a beer
                Get my Book: MODX:The Official Guide
                MODX info for everyone: http://bobsguides.com/modx.html
                My MODX Extras
                Bob's Guides is now hosted at A2 MODX Hosting
                • 38290
                • 712 Posts
                Remember though we are trying to prevent access. Would Bruno's method prevent them from accessing via a direct URL, or just not present the given page in a getResources menu?
                  jpdevries
                  • 1331
                  • 129 Posts
                  A lot of good ideas here. I had originally thought of making the actual page content conditional based on the groups, but was still stuck with how to get resources in and out of them based on date. Bruno's method looks like it could be a good start. But I think some combination of everything here may do the trick.

                  Thanks a bunch, guys, for the input. I'm going to play with this and report back.
                    • 1331
                    • 129 Posts
                    Oh, you're right JP. It looks like Bruno's method is referring to the getResources. I already have that working. The snippet that I'm comparing my publishedon date to is simply

                    echo date(strtotime("-60 days"));


                    Works perfectly for conditionally displaying the getResources list to the different user groups.
                      • 1331
                      • 129 Posts
                      (BobRay, I think the snippet you posted is what I was referring to earlier. I read all of these at one time).

                      I think conditionally handling the "now" to "pageAge" comparison on the page would give me the functionality I need without necessarily having to rely on built-in ACLs.

                      I'm going to try it out now.