Jump to content

quickjeff

Members
  • Posts

    323
  • Joined

  • Last visited

Posts posted by quickjeff

  1. Ryan had shown us a nice way to setup user front end login etc. I came across an issue with a client in which I have setup SMTP for a method of delivering notification emails.  However, using Ryan's suggested /reset-pass/ page, the user is not getting notifications. Any light on enabling SMTP for the reset-pass page as well?

  2. With the assistance of Macrura and another thread in this awesome community, I successfully have also been able to manipulate what menu items display in the navigation based on the users page role. Example is using bootstrap navigation.
     

    hey quickjeff - maybe you could post your final code, to see how it was adjust for the use case?
    cheers!

    Code below:

     

    <div id="navbar" class="navbar-collapse collapse">
              <?php
    
    			function renderChildrenOf($pa, $output = '', $level = 0)
    			{
    			    $output = '';
    			    $level++;
    			
    			    foreach ($pa as $child) {
    			        $atoggle = '';
    			        $class = '';
    			        
    
    			         //Check if the user is allowed to view nav links
    			        $menuVis = true;
    					if($child->page_roles) {	    
    					    foreach($child->page_roles as $cmr) {
    						    $menuVis = false;
    						    $cmrRole = wire('roles')->get("$cmr->name");
    							if (wire("user")->hasRole("$cmrRole") ) {
    								$menuVis = true;
    								break;
    							}
    						}
    					} 
    					if($menuVis == false) continue;
    			        
    
    			
    			        if ($child->numChildren && count($child->parents) == 1) {
    			            $class .= 'dropdown';
    			            $atoggle .= ' class="dropdown-toggle" data-toggle="dropdown"';
    			        } else if ($child->numChildren && count($child->parents) > 1) {
    			            $class .= 'dropdown-submenu';
    			            $atoggle .= ' class="dropdown-toggle"';
    			        } else if ($child->numChildren && $child->id != 1 ) {
    			            $class .= 'dropdown-menu';
    			        }
    			
    			// Makes the current page and it's top level parent add an active class
    			$class .= ($child === wire("page") || $child === wire("page")->rootParent) ? " active" : '';
    			$class = strlen($class) ? " class='" . trim($class) . "'" : '';
    			
    		if ($child->numChildren && count($child->parents) == 1) {
    			            // Add Caret if have children
    		$output .= "<li$class><a href='$child->url'$atoggle>$child->title <b class='caret'></b></a>";
    			        } else if ($child->numChildren && count($child->parents) > 1) {
    		$output .= "<li$class><a tabindex='-1' href='$child->url'$atoggle>$child->title</a>";
    			        } else {
    			            $output .= "<li$class><a href='$child->url'$atoggle>$child->title</a>";
    			        }
    			
    		// If this child is a parent and not the root page, then render it's children in menu
    			        if ($child->numChildren && $child->id != 1) {
    			            $output .= renderChildrenOf($child->children, $output, $level);
    			        }
    			        $output .= '</li>';
    			    }
    			    $outerclass = ($level == 1) ? "nav navbar-nav" : 'dropdown-menu';
    			    return "<ul class='$outerclass'>$output</ul>";
    			}
    
    			// bundle up the first level pages and prepend the root home page
    			$homepage = $pages->get(1);
    			$pa = $homepage->children;
    			
    			$pa = $pa->prepend($homepage);
    			
    			echo renderChildrenOf($pa); ?>
    		  
    		         
            </div>
    
  3. Hi Guys, 

    So I have this navigation setup for a site, it can be found here:

    https://processwire.com/talk/topic/5680-bootstrap-3-navigation-with-multiple-leveltier-fix/

    However, I have also added this module to the site which works great:

    http://modules.processwire.com/modules/custom-page-roles/

    Any ideas for displaying the navigation links based on the logged in users ability to see the page?

    Figured I would ask around before I dove right in. 

    Here is the nav code:

    function renderChildrenOf($pa, $output = '', $level = 0)
    {
        $output = '';
        $level++;
    
        foreach ($pa as $child) {
            $atoggle = '';
            $class = '';
    
            if ($child->numChildren && count($child->parents) == 1) {
                $class .= 'dropdown';
                $atoggle .= ' class="dropdown-toggle" data-toggle="dropdown"';
            } else if ($child->numChildren && count($child->parents) > 1) {
                $class .= 'dropdown-submenu';
                $atoggle .= ' class="dropdown-toggle"';
            } else if ($child->numChildren && $child->id != 1 ) {
                $class .= 'dropdown-menu';
            }
    
            // Makes the current page and it's top level parent add an active class
            $class .= ($child === wire("page") || $child === wire("page")->rootParent) ? " active" : '';
            $class = strlen($class) ? " class='" . trim($class) . "'" : '';
    
            if ($child->numChildren && count($child->parents) == 1) {
                // Add Caret if have children
                $output .= "<li$class><a href='$child->url'$atoggle>$child->title <b class='caret'></b></a>";
            } else if ($child->numChildren && count($child->parents) > 1) {
                $output .= "<li$class><a tabindex='-1' href='$child->url'$atoggle>$child->title</a>";
            } else {
                $output .= "<li$class><a href='$child->url'$atoggle>$child->title</a>";
            }
    
            // If this child is itself a parent and not the root page, then render it's children in their own menu too...
            if ($child->numChildren && $child->id != 1) {
                $output .= renderChildrenOf($child->children, $output, $level);
            }
            $output .= '</li>';
        }
        $outerclass = ($level == 1) ? "nav navbar-nav" : 'dropdown-menu';
        return "<ul class='$outerclass'>$output</ul>";
    }
    
    // bundle up the first level pages and prepend the root home page
    $homepage = $pages->get(1);
    $pa = $homepage->children;
    //$pa = $pa->prepend($homepage);
    
    // Set the ball rolling...
    echo renderChildrenOf($pa); ?>
    
  4. Hey Adrian,

    I saw that post before posting here but ended realizing that the member was asking to replace the username.

    However, I want the user to either login using a username or their email. So basically, checking the input field for either one.

    Similar to what the temp_pass does. However, still haven't slapped together a solution.

    Thanks!

  5. Hi Guys, 

    So I have implemented Ryan's template setup for login, profile,  logout and reset pass. 

    My question is, what if we want to allow the user to login with the username or their email, which most forms do nowadays. 

    Any advice on the approach. 

    Essentially, 1 form, 2 input fields, 1 submit button. 

    Here is the template being used to handle login as of now:

    if($user->isLoggedin()) $session->redirect('/profile/'); 
    if($input->post->username && $input->post->pass) {
      $username = $sanitizer->username($input->post->username); 
      $pass = $input->post->pass; 
      $u = $users->get($username); 
      if($u->id && $u->tmp_pass && $u->tmp_pass === $pass) {
        // user logging in with tmp_pass, so change it to be their real pass
        $u->of(false);
        $u->pass = $u->tmp_pass;
        $u->save();
        $u->of(true);
      }
      $u = $session->login($username, $pass); 
      if($u) {
        // user is logged in, get rid of tmp_pass
        $u->of(false);
        $u->tmp_pass = '';
        $u->save();
        // now redirect to the profile edit page
        $session->redirect('/profile/'); 
      }
    }
    
    // present the login form
    $headline = $input->post->username ? "Login failed" : "Please login";
    $page->body = "
      <h2>$headline</h2>
      <form action='./' method='post'>
      <p>
      <label>Username <input type='text' name='username'></label>
      <label>Password <input type='password' name='pass'></label>
      </p>
      <input type='submit'>
      </form>
      <p><a href='/reset-pass/'>Forgot your password?</a></p>
    ";
    
    include("./main.php"); // main markup template
    
  6. Hi Guys,

    I am working on a project for a startup company. I will be building a portal for users to access company related information. I am required to connect the portal to an LMS which is a learning management system. I am looking to hire someone to assist with the SSO since I have a lot of work already with the portal. The portal will be built on ProcessWire and require user management.

    Please message me if you are interested in helping out. I would like to get some quotes before the weekend is over.

    Looking to start ASAP on this project.

    Let me know if you have any questions.

    Also note, once we have the SSO out of the way, more work may arise from this project, since our timeline is somewhat short.

    Thanks!

  7. @marcus

    Totally agree, a generic OAuth module would be nice. You are also correct with the Github example you did, which I strongly thank you for!!! It's a combination of that as well as the Twitter version. Also, tested another version I created with a combination of all, using LinkedIn, I get the same issues. It logs into the original users account when ProcessWire was first setup changing the password, as if it was overwriting the users account. In Googles case, it says you can view certain items including the email but not sure if you can get it. In LinkedIn the documentation states you can get the email.

    Hoping to make some breakthrough fairly soon.

    :-(

  8. Hi Guys, 

    So after reading multiple threads and searching for a solution required for a project, I decided to build a module to enable users to login to the CMS via their gmail account and hopefully the module can also be altered for LinkedIn and other Social accounts.  Unfortunately the Facebook module does give you a Facebook ID and assigns the Facebook Role however I would like to assign the role, get the users email and create the user if its not in the system.  

    I have basically taken the Facebook Login Module created by apeisa and manipulated the module to somewhat work with GMAIL.

    What it does now:  It allows you to login but doesn't pull any data from GMAIL. Therefore it automatically logins in to the first account created in ProcessWire, but oddly changes the password, Im sure its due to the line of code in the module that is set to generate a random password via sha1.

    What I need it to do: If the user isn't in the system, get the gmail email, add the gmail email to the email field in ProcessWire, assign the gmail role or whatever role I want to auto assign it and log them in.

    ​My resources from Google: https://developers.google.com/accounts/docs/OAuth2

    Please note, I will be updating the code as I make progress but please give input or help if you can. As always, thank you so much to everyone for their input and help, especially apeisa and craig a rodway for giving some direction initially.

    Here is what I have so far:

    <?php
    
    class GoogleLogin extends WireData implements Module, ConfigurableModule {
    
    	const name = 'google-login';
    
           //the google ID isn't used in Gmail so I am sure this will go away. 
    	const fieldName = 'google_id';
    
    	public static function getModuleInfo() {
    		return array(
    		 "title" => "Google Login for Website",
    		 "version" => 001,
    		 "summary" => "Allows users to authenticate through their GMAIL account.",
    		 "autoload" => false
    		);
    	}
    
    	public function init() {
    
    	}
    
    	public function execute() {
    
    		// Prevent association of Google Account to an existing user
    		if ($this->user->isLoggedin()) {
    			echo "Already logged in.";
    			return;
    		}
    
    		$client_id = $this->googleAppId;
    		$app_secret = $this->googleAppSecret;
    		$redirect_uri = $this->page->httpUrl;
    
    		$code = $_REQUEST["code"];
    
    		if(empty($code)) {
    			$_SESSION['state'] = md5(uniqid(rand(), TRUE)); //CSRF protection
    			$dialog_url = "https://accounts.google.com/o/oauth2/auth?client_id=" . $client_id . "&redirect_uri=" . $redirect_uri . "&state=" . $_SESSION['state'] . "&scope=profile email&response_type=code";
    			echo("<script> top.location.href='" . $dialog_url . "'</script>");
    		}
    
    		if($_SESSION['state'] && ($_SESSION['state'] === $_REQUEST['state'])) {
    			$token_url = "https://accounts.google.com/o/oauth2/auth/access_token?"
    				. "client_id=" . $client_id . "&redirect_uri=" . urlencode($redirect_uri)
    				. "&client_secret=" . $app_secret . "&code=" . $code;
    
    			$response = file_get_contents($token_url);
    			$params = null;
    			parse_str($response, $params);
    
    			$access_url = "https://accounts.google.com/o/oauth2/auth/user?access_token=" . $params['access_token'];
    
    			// Add stream context
    			$options  = array('http' => array('user_agent'=> $_SERVER['HTTP_USER_AGENT']));
    			$context  = stream_context_create($options);
    
    			$ghUserData = json_decode(file_get_contents($access_url, false, $context));
    
    			$this->processLogin($ghUserData);
    		}
    		else {
    			echo("The state does not match. You may be a victim of CSRF.");
    		}
    		
    	}
    
    	public function processLogin($ghUserData) {
    		$id = $ghUserData->id;
    		$u = $this->users->get("google_id=$id");
    
    		// First we create random pass to use in login
    		$uniqid = uniqid();
    		$pass = sha1($uniqid . $id . $ghUserData->updated_at);
    
    		// User has logged in earlier with Google id, great news let's login
    		if ($u->id) {
    			$u->of(false);
    			$u->pass = $pass;
    			$u->addRole(self::name);
    			$u->save();
    		}
    
    		// User has not logged in before and autogenerate is on
    		else if (!$this->disableAutogenerate) {
    			$name = $this->sanitizer->pageName($ghUserData->name, true);
    			$u = $this->users->get("name=$name");
    
    			// All seems to be fine, let's create the user
    			$u = new User;
    			$u->name = $name;
    			$u->google_id = $ghUserData->id;
    			$u->pass = $pass;
    			$u->addRole(self::name);
    			$u->save();
    		} else {
    			echo $this->renderCreateUserForm();
    		}
    
    		$this->session->login($u->name, $pass);
    		$p = $this->pages->get($this->redirectPage);
    		if (!$p->id) {
    			$p = $this->pages->get(1);
    		}
    		$this->session->redirect($p->httpUrl);
    	}
    
    	public function renderCreateUserForm() {
    
    	}
    
    	static public function getModuleConfigInputfields(Array $data) {
    		$fields = new InputfieldWrapper();
    
    		// since this is a static function, we can't use $this->modules, so get them from the global wire() function
    		$modules = wire('modules');
    
    		$field = $modules->get("InputfieldText");
    		$field->attr('name', 'googleAppId');
    		$field->attr('value', $data['googleAppId']);
    		$field->label = "Google App Id";
    		$field->description = 'Client Id for your project. You can create one from here: https://console.developers.google.com';
    		$fields->add($field);
    
    		$field = $modules->get("InputfieldText");
    		$field->attr('name', 'googleAppSecret');
    		$field->attr('value', $data['googleAppSecret']);
    		$field->label = "Google App Secret";
    		$field->description = 'Client Secret for your project. Available in your project console here: https://console.developers.google.com';
    		$fields->add($field);
    
    		/*
    		$field = $modules->get("InputfieldCheckbox");
    		$field->attr('name', 'disableAutogenerate');
    		$field->attr('value', 1);
    		$field->attr('checked', empty($data['disableAutogenerate']) ? '' : 'checked');
    		$field->label = "Don't set username automatically, but let the user choose username when doing the first login";
    		$fields->add($field);
    		*/
    
    		$field = $modules->get("InputfieldPageListSelect");
    		$field->attr('name', 'redirectPage');
    		$field->attr('value', $data['redirectPage']);
    		$field->label = "Page where user is redirected after succesful login";
    		$fields->add($field);
    
    		return $fields;
    
    	}
    
    	public function install() {
    
    		$name = self::name;
    		$fieldName = self::fieldName;
    
    		$page = $this->pages->get("/$name/");
    		if($page->id) throw new WireException("There is already a page installed called '/$name/'");
    
    		$template = $this->templates->get($name);
    		if($template) throw new WireException("There is already a template installed called '$name'");
    
    		$fieldgroup = $this->fieldgroups->get($name);
    		if($fieldgroup) throw new WireException("There is already a fieldgroup installed called '$name'");
    
    		$field = $this->fields->get($fieldName);
    		if($field) throw new WireException("There is already a field installed called '$fieldName'");
    
    		$role = $this->roles->get($name);
    		if (!$role->id) {
    			$this->roles->add($name);
    			$this->message("Create role called $name");
    		}
    
    		$fieldgroup = new Fieldgroup();
    		$fieldgroup->name = $name;
    		$title = $this->fields->get('title');
    		if($title) $fieldgroup->add($title);
    		$fieldgroup->save();
    
    		$template = new Template();
    		$template->name = $name;
    		$template->fieldgroup = $fieldgroup;
    		$template->allowPageNum = 1;
    		$template->save();
    		$this->message("Installed template $name");
    
    		$page = new Page();
    		$page->template = $template;
    		$page->parent = '/';
    		$page->name = $name;
    		$page->title = "Google Login";
    		$page->addStatus(Page::statusHidden);
    		$page->save();
    		$this->message("Installed page $page->path");
    
    		$basename = $name . ".php";
    		$src = $this->config->paths->SessionGoogleLogin . $basename;
    		$dst = $this->config->paths->templates . $basename;
    		if(@copy($src, $dst)) {
    			$this->message("Installed template file $basename");
    		}	else {
    			$this->error("Templates directory is not writable so we were unable to auto-install the $basename template file.");
    			$this->error("To complete the installation please copy $basename from $src to $dst");
    		}
    
    		// Create hidden inputfield
    		$input = new InputfieldText;
    		$input->set('collapsed', Inputfield::collapsedHidden);
    
    		// Create field called Google and set details and inputfield
    		$f = new Field();
    		$f->type = $this->modules->get("FieldtypeText");
    		$f->name = $fieldName;
    		$f->label = 'Google ID';
    		$f->description = 'Stores Google id for user';
    		$f->inputfield = $input;
    		$f->save();
    
    		// Add the field to user fieldgroup (basically means user template in this context)
    		$fg = $this->fieldgroups->get('user');
    		$fg->add($f);
    		$fg->save();
    	}
    
    	public function uninstall() {
    
    	}
    }
    
    
    • Like 4
  9. Hi guys, I have been reading through the forum posts and see that this thread relates to what I need to build. I am basically building an internal site for a company.  They are going to be adding an LMS.  Essentially they want SSO single sign-on.  I mentioned that the LMS they should have OAuth, any other suggestions or guidance?  I can see that the Facebook Module is very nice and a quick fix but this will basically require me to build a module that works in the same fashion. Only difference, Facebook developers portal pretty much makes it easier. :undecided:

  10. It looks like LinkedIn use OAuth for this process, just like Facebook and Twitter and GitHub.

    There are ProcessWire modules that handle those networks:

    I would start by looking at those, learning how they work, and then building one for LinkedIn that meets your needs :)

    Correct, I was already looking at Facebook module seems like a straight forward build.  Appreciate the link and suggestions!

  11. Hi Guys, 

    Has anyone used LinkedIn for Single Sign-In?  I will be building a site for a company and looking to use LinkedIn for single sign in.  I will be diving into this project in the next few days but wanted to know if anyone has done this yet? Any advice would be appreciated before I start coding away.  ;)

  12. Hi Mike, we must have missed this last piece, since that was the last element added to replace a previous message. We simply commented out the previous message temporarily as we have something sweet cooking up to release soon!

    Thanks for the catch, it is now fixed! 

    • Like 1
×
×
  • Create New...