diff --git a/hr_linkedin_recruitment/README.rst b/hr_linkedin_recruitment/README.rst index 30e11c072..48b4d7060 100644 --- a/hr_linkedin_recruitment/README.rst +++ b/hr_linkedin_recruitment/README.rst @@ -18,17 +18,24 @@ The module integrates LinkedIn with Odoo HR Recruitment. * Profile URL of Candidates. * Automate Odoo HRMS with LinkedIn. - Company ------- * `Cybrosys Technologies `__ +Developers +---------- +* `Nilmar Shereef `__ +* `Jesni Banu `__ + Contact ------- * Mail Contact : odoo@cybrosys.com * Mail Contact : shereef@cybrosys.in * Mail Contact : info@cybrosys.com +Related Blog +------- +* `Cybrosys LinkedIn Blog `__ Further information =================== HTML Description: ``__ diff --git a/hr_linkedin_recruitment/__manifest__.py b/hr_linkedin_recruitment/__manifest__.py index d9cf42523..9558d344a 100644 --- a/hr_linkedin_recruitment/__manifest__.py +++ b/hr_linkedin_recruitment/__manifest__.py @@ -25,7 +25,7 @@ 'summary': "Integrates LinkedIn with HR Recruitment", 'description': "Basic module for LnkedIn-HR Recruitment connector", 'category': 'Generic Modules/Human Resources', - 'version': "10.0.1.1.0", + 'version': "10.0.2.0.0", 'depends': ['hr_recruitment', 'auth_oauth'], 'author': 'Cybrosys Techno Solutions', 'company': 'Cybrosys Techno Solutions', diff --git a/hr_linkedin_recruitment/doc/RELEASE_NOTES.md b/hr_linkedin_recruitment/doc/RELEASE_NOTES.md new file mode 100644 index 000000000..b24b5dfe5 --- /dev/null +++ b/hr_linkedin_recruitment/doc/RELEASE_NOTES.md @@ -0,0 +1,14 @@ +## Module + +#### 19.05.2018 +#### Version 10.0.2.0.0 +##### FIX +- Redirect url +- Handler for wrong password +- Handler import error + + +#### 28.04.2018 +#### Version 10.0.1.0.0 +##### ADD +- Initial commit for LinkedIn-Odoo Integration diff --git a/hr_linkedin_recruitment/doc/requirment.txt b/hr_linkedin_recruitment/doc/requirment.txt index ef092c744..6a8ad0917 100644 --- a/hr_linkedin_recruitment/doc/requirment.txt +++ b/hr_linkedin_recruitment/doc/requirment.txt @@ -1,5 +1,8 @@ Odoo integration module "hr_linkedin_recruitment" depends on the several external python package. Please ensure that listed packaged has installed in your system: -* linkedin -* mechanize \ No newline at end of file +* python-linkedin (sudo python-linkedin) +* mechanize (sudo pip install mechanize) + + + diff --git a/hr_linkedin_recruitment/models/hr_job.py b/hr_linkedin_recruitment/models/hr_job.py index 7fb0bc72e..767a312e5 100644 --- a/hr_linkedin_recruitment/models/hr_job.py +++ b/hr_linkedin_recruitment/models/hr_job.py @@ -25,6 +25,7 @@ _logger = logging.getLogger(__name__) try: import mechanize from linkedin import linkedin + from mechanize_op import MechanizeRedirectHandler except ImportError: _logger.error('Odoo module hr_linkedin_recruitment depends on the several external python package' @@ -34,8 +35,7 @@ import requests import json import urlparse from odoo import models, fields, api, _ -from odoo.exceptions import ValidationError -from mechanize_op import MechanizeRedirectHandler +from odoo.exceptions import ValidationError, Warning class HrJobShare(models.Model): @@ -59,15 +59,25 @@ class HrJobShare(models.Model): has_access_url = 'https://api.linkedin.com/v1/companies/%s/relation-to-viewer/is-company-share-enabled?format=json'%(li_credential['page_id']) page_share_url = 'https://api.linkedin.com/v1/companies/%s/shares?format=json'%(li_credential['page_id']) - response = self.has_acces_request('GET', has_access_url, access_token) - access_response_text = response.json() + access_response = self.has_acces_request('GET', has_access_url, access_token) + access_response_text = access_response.json() if access_response_text: response = self.share_request('POST', page_share_url, access_token, data=json.dumps(share_data)) share_response_text = response.json() share_response_code = response.status_code if share_response_code == 201: self.update_key = share_response_text['updateKey'] + else: + raise Warning("You have no share access in company page.!") + def has_acces_request(self, method, has_access_url, access_token): + """ Function will return TRUE if credentials user has the access to update """ + headers = {'x-li-format': 'json', 'Content-Type': 'application/json'} + params = {} + params.update({'oauth2_access_token': access_token}) + kw = dict(params=params, headers=headers, timeout=60) + req_response = requests.request(method.upper(), has_access_url, **kw) + return req_response def share_request(self, method, page_share_url, access_token, data): """ Function will return UPDATED KEY , [201] if sharing is OK """ @@ -93,15 +103,15 @@ class HrJobShare(models.Model): li_credential['page_id'] = self.env['ir.values'].get_default('hr.recruitment.config.settings', 'company_page_id') else: - raise exceptions.Warning(_('Please fill up company page ID in LinkedIn Credential settings.')) + raise Warning(_('Please fill up company page ID in LinkedIn Credential settings.')) if self.env['ir.values'].get_default('hr.recruitment.config.settings', 'li_username'): li_credential['un'] = self.env['ir.values'].get_default('hr.recruitment.config.settings', 'li_username') else: - raise exceptions.Warning(_('Please fill up username in LinkedIn Credential settings.')) + raise Warning(_('Please fill up username in LinkedIn Credential settings.')) if self.env['ir.values'].get_default('hr.recruitment.config.settings', 'li_password'): li_credential['pw'] = self.env['ir.values'].get_default('hr.recruitment.config.settings', 'li_password') else: - raise exceptions.Warning(_('Please fill up password in LinkedIn Credential settings.')) + raise Warning(_('Please fill up password in LinkedIn Credential settings.')) # Browser Data Posting And Signing br = mechanize.Browser() @@ -109,7 +119,7 @@ class HrJobShare(models.Model): br.handler_classes['_redirect'] = MechanizeRedirectHandler br.set_handle_redirect(True) br.set_handle_robots(False) - return_uri = 'http://0.0.0.0:8010' + return_uri = self.env['ir.config_parameter'].sudo().get_param('web.base.url') li_permissions = ['r_basicprofile', 'r_emailaddress', 'w_share', 'rw_company_admin'] auth = linkedin.LinkedInAuthentication(li_credential['api_key'], li_credential['secret_key'], @@ -117,11 +127,15 @@ class HrJobShare(models.Model): li_permissions) br.open(auth.authorization_url) br.select_form(nr=0) - + print "li_credential", li_credential br.form['session_key'] = li_credential['un'] br.form['session_password'] = li_credential['pw'] r = br.submit() - auth.authorization_code = urlparse.parse_qs(urlparse.urlsplit(r.geturl()).query)['code'] + try: + auth.authorization_code = urlparse.parse_qs(urlparse.urlsplit(r.geturl()).query)['code'] + except: + raise Warning("Please cross check your username and password.!") + li_suit_credent = {} li_suit_credent['access_token'] = str(auth.get_access_token().access_token) li_suit_credent['li_credential'] = li_credential diff --git a/hr_linkedin_recruitment/models/mechanize_op.py b/hr_linkedin_recruitment/models/mechanize_op.py index d03dd5386..0b439ad35 100644 --- a/hr_linkedin_recruitment/models/mechanize_op.py +++ b/hr_linkedin_recruitment/models/mechanize_op.py @@ -21,52 +21,56 @@ # ################################################################################### import logging +from urllib2 import HTTPError _logger = logging.getLogger(__name__) try: import mechanize -except ImportError: - _logger.error('Odoo module hr_linkedin_recruitment depends on the several external python package' - 'Please read the doc/requirement.txt file inside the module.') -import re -from mechanize import _response -from mechanize import _rfc3986 + from mechanize import _response + from mechanize import _rfc3986 + import re + + + class MechanizeRedirectHandler(mechanize.HTTPRedirectHandler): + def http_error_302(self, req, fp, code, msg, headers): + # Code from mechanize._urllib2_fork.HTTPRedirectHandler: + if 'location' in headers: + newurl = headers.getheaders('location')[0] + elif 'uri' in headers: + newurl = headers.getheaders('uri')[0] + else: + return + newurl = _rfc3986.clean_url(newurl, "latin-1") + newurl = _rfc3986.urljoin(req.get_full_url(), newurl) + new = self.redirect_request(req, fp, code, msg, headers, newurl) + if new is None: + return -class MechanizeRedirectHandler(mechanize.HTTPRedirectHandler): - def http_error_302(self, req, fp, code, msg, headers): - # Code from mechanize._urllib2_fork.HTTPRedirectHandler: - if 'location' in headers: - newurl = headers.getheaders('location')[0] - elif 'uri' in headers: - newurl = headers.getheaders('uri')[0] - else: - return - newurl = _rfc3986.clean_url(newurl, "latin-1") - newurl = _rfc3986.urljoin(req.get_full_url(), newurl) + if hasattr(req, 'redirect_dict'): + visited = new.redirect_dict = req.redirect_dict + if (visited.get(newurl, 0) >= self.max_repeats or + len(visited) >= self.max_redirections): + raise HTTPError(req.get_full_url(), code, + self.inf_msg + msg, headers, fp) + else: + visited = new.redirect_dict = req.redirect_dict = {} + visited[newurl] = visited.get(newurl, 0) + 1 - new = self.redirect_request(req, fp, code, msg, headers, newurl) - if new is None: - return + fp.read() + fp.close() - if hasattr(req, 'redirect_dict'): - visited = new.redirect_dict = req.redirect_dict - if (visited.get(newurl, 0) >= self.max_repeats or - len(visited) >= self.max_redirections): - raise HTTPError(req.get_full_url(), code, - self.inf_msg + msg, headers, fp) - else: - visited = new.redirect_dict = req.redirect_dict = {} - visited[newurl] = visited.get(newurl, 0) + 1 + # If the redirected URL doesn't match + new_url = new.get_full_url() + if not re.search('^http(?:s)?\:\/\/.*www\.linkedin\.com', new_url): + return _response.make_response('', headers.items(), new_url, 200, 'OK') + else: + return self.parent.open(new) - fp.read() - fp.close() + http_error_301 = http_error_303 = http_error_307 = http_error_302 + http_error_refresh = http_error_302 + +except ImportError: + _logger.warning('Odoo module hr_linkedin_recruitment depends on the several external python package' + 'Please read the doc/requirement.txt file inside the module.') - # If the redirected URL doesn't match - new_url = new.get_full_url() - if not re.search('^http(?:s)?\:\/\/.*www\.linkedin\.com', new_url): - return _response.make_response('', headers.items(), new_url, 200, 'OK') - else: - return self.parent.open(new) - http_error_301 = http_error_303 = http_error_307 = http_error_302 - http_error_refresh = http_error_302