예제 #1
0
파일: test_user.py 프로젝트: adamrp/qiita
    def test_messages(self):
        add_system_message('SYS MESSAGE', datetime.now())
        user = User('*****@*****.**')
        obs = user.messages()
        exp_msg = [
            (4, 'SYS MESSAGE'),
            (1, 'message 1'),
            (2, 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. '
                'Pellentesque sed auctor ex, non placerat sapien. Vestibulum '
                'vestibulum massa ut sapien condimentum, cursus consequat diam'
                ' sodales. Nulla aliquam arcu ut massa auctor, et vehicula '
                'mauris tempor. In lacinia viverra ante quis pellentesque. '
                'Nunc vel mi accumsan, porttitor eros ut, pharetra elit. Nulla'
                ' ac nisi quis dui egestas malesuada vitae ut mauris. Morbi '
                'blandit non nisl a finibus. In erat velit, congue at ipsum '
                'sit amet, venenatis bibendum sem. Curabitur vel odio sed est '
                'rutrum rutrum. Quisque efficitur ut purus in ultrices. '
                'Pellentesque eu auctor justo.'),
            (3, 'message <a href="#">3</a>')]
        self.assertEqual([(x[0], x[1]) for x in obs], exp_msg)
        self.assertTrue(all(x[2] < datetime.now() for x in obs))
        self.assertFalse(all(x[3] for x in obs))
        self.assertEqual([x[4] for x in obs], [True, False, False, False])

        obs = user.messages(1)
        exp_msg = ['SYS MESSAGE']
        self.assertEqual([x[1] for x in obs], exp_msg)
예제 #2
0
    def post(self, code):
        message = ""
        level = ""
        page = "change_lost_pass.html"
        user = None

        try:
            user = User(self.get_argument("email"))
        except QiitaDBUnknownIDError:
            message = "Unable to reset password"
            level = "danger"
        else:
            newpass = self.get_argument("newpass")
            try:
                changed = user.change_forgot_password(code, newpass)
            except IncorrectPasswordError:
                message = "The new password is not valid. Try again."
                changed = False
            except QiitaDBError:
                message = "Invalid code. Request a new one."
                changed = False

            if changed:
                message = ("Password reset successful. Please log in to "
                           "continue.")
                level = "success"
                page = "index.html"
            else:
                if message != "":
                    message = ("Unable to reset password. Most likely your "
                               "email is incorrect or your reset window has "
                               "timed out.")
                level = "danger"

        self.render(page, message=message, level=level, code=code)
예제 #3
0
    def post(self):
        message = ""
        level = ""
        page = "lost_pass.html"
        user_id = None

        try:
            user = User(self.get_argument("email"))
        except QiitaDBUnknownIDError:
            message = "ERROR: Unknown user."
            level = "danger"
        else:
            user_id = user.id
            user.generate_reset_code()
            info = user.info
            try:
                send_email(user.id, "Qiita: Password Reset", "Please go to "
                           "the following URL to reset your password: \n"
                           "%s/auth/reset/%s  \nYou "
                           "have 30 minutes from the time you requested a "
                           "reset to change your password. After this period, "
                           "you will have to request another reset." %
                           (qiita_config.base_url, info["pass_reset_code"]))
                message = ("Check your email for the reset code.")
                level = "success"
                page = "index.html"
            except Exception as e:
                message = ("Unable to send email. Error has been registered. "
                           "Your password has not been reset.")
                level = "danger"
                LogEntry.create('Runtime', "Unable to send forgot password "
                                "email: %s" % str(e), info={'User': user.id})

        self.render(page, user=user_id, message=message, level=level)
예제 #4
0
    def post(self, code):
        message = ""
        level = ""
        page = "change_lost_pass.html"
        user = None

        try:
            user = User(self.get_argument("email"))
        except QiitaDBUnknownIDError:
            message = "Unable to reset password"
            level = "danger"
        else:
            newpass = self.get_argument("newpass")
            changed = user.change_forgot_password(code, newpass)

            if changed:
                message = ("Password reset successful. Please log in to "
                           "continue.")
                level = "success"
                page = "index.html"
            else:
                message = ("Unable to reset password. Most likely your email "
                           "is incorrect or your reset window has timed out.")

                level = "danger"

        self.render(page, message=message, level=level, code=code)
예제 #5
0
    def post(self):
        message = ""
        level = ""
        page = "lost_pass.html"
        user_id = None

        try:
            user = User(self.get_argument("email"))
        except QiitaDBUnknownIDError:
            message = "ERROR: Unknown user."
            level = "danger"
        else:
            user_id = user.id
            user.generate_reset_code()
            info = user.info
            try:
                send_email(user.id, "Qiita: Password Reset", "Please go to "
                           "the following URL to reset your password: "******"http://qiita.colorado.edu/auth/reset/%s" %
                           info["pass_reset_code"])
                message = ("Check your email for the reset code.")
                level = "success"
                page = "index.html"
            except Exception as e:
                message = ("Unable to send email. Error has been registered. "
                           "Your password has not been reset.")
                level = "danger"
                LogEntry.create('Runtime', "Unable to send forgot password "
                                "email: %s" % str(e), info={'User': user.id})

        self.render(page, user=user_id, message=message, level=level)
예제 #6
0
    def test_get(self):
        response = self.get('/auth/verify/SOMETHINGHERE?email=test%40foo.bar')
        self.assertEqual(response.code, 200)

        User.create('*****@*****.**', 'Somesortofpass')
        response = self.get('/auth/verify/SOMETHINGHERE?email=new%40test.bar')
        self.assertEqual(response.code, 200)
예제 #7
0
    def test_verify_code(self):
        sql = ("insert into qiita.qiita_user values ('*****@*****.**', '1', "
               "'testtest', 'testuser', '', '', '', 'verifycode', 'resetcode'"
               ",null)")
        self.conn_handler.execute(sql)
        self.assertFalse(User.verify_code('*****@*****.**', 'wrongcode',
                                          'create'))
        self.assertFalse(User.verify_code('*****@*****.**', 'wrongcode',
                                          'reset'))

        self.assertTrue(User.verify_code('*****@*****.**', 'verifycode',
                                         'create'))
        self.assertTrue(User.verify_code('*****@*****.**', 'resetcode',
                                         'reset'))

        # make sure errors raised if code already used or wrong type
        with self.assertRaises(QiitaDBError):
            User.verify_code('*****@*****.**', 'verifycode', 'create')
        with self.assertRaises(QiitaDBError):
            User.verify_code('*****@*****.**', 'resetcode', 'reset')

        with self.assertRaises(IncompetentQiitaDeveloperError):
            User.verify_code('*****@*****.**', 'fakecode', 'badtype')

        # make sure default analyses created
        sql = ("SELECT email, name, description, dflt FROM qiita.analysis "
               "WHERE email = '*****@*****.**'")
        obs = self.conn_handler.execute_fetchall(sql)
        exp = [['*****@*****.**', '[email protected]', 'dflt', True],
               ['*****@*****.**', '[email protected]', 'dflt', True]]
        self.assertEqual(obs, exp)
예제 #8
0
파일: test_user.py 프로젝트: adamrp/qiita
    def test_verify_code(self):
        add_system_message("TESTMESSAGE_OLD", datetime.now())
        add_system_message("TESTMESSAGE",
                           datetime.now() + timedelta(seconds=59))
        sql = ("insert into qiita.qiita_user values ('*****@*****.**', '1', "
               "'testtest', 'testuser', '', '', '', 'verifycode', 'resetcode'"
               ",null)")
        self.conn_handler.execute(sql)

        self.assertFalse(User.verify_code('*****@*****.**', 'wrongcode',
                                          'create'))
        self.assertFalse(User.verify_code('*****@*****.**', 'wrongcode',
                                          'reset'))

        self.assertTrue(User.verify_code('*****@*****.**', 'verifycode',
                                         'create'))
        self.assertTrue(User.verify_code('*****@*****.**', 'resetcode',
                                         'reset'))

        # make sure errors raised if code already used or wrong type
        with self.assertRaises(QiitaDBError):
            User.verify_code('*****@*****.**', 'verifycode', 'create')
        with self.assertRaises(QiitaDBError):
            User.verify_code('*****@*****.**', 'resetcode', 'reset')

        with self.assertRaises(IncompetentQiitaDeveloperError):
            User.verify_code('*****@*****.**', 'fakecode', 'badtype')

        # make sure default analyses created
        sql = ("SELECT email, name, description, dflt FROM qiita.analysis "
               "WHERE email = '*****@*****.**'")
        obs = self.conn_handler.execute_fetchall(sql)
        exp = [['*****@*****.**', '[email protected]', 'dflt', True],
               ['*****@*****.**', '[email protected]', 'dflt', True]]
        self.assertEqual(obs, exp)

        # Make sure default analyses are linked with the portal
        sql = """SELECT COUNT(1)
                 FROM qiita.analysis
                    JOIN qiita.analysis_portal USING (analysis_id)
                    JOIN qiita.portal_type USING (portal_type_id)
                 WHERE email = '*****@*****.**' AND dflt = true"""
        self.assertEqual(self.conn_handler.execute_fetchone(sql)[0], 2)

        # Make sure new system messages are linked to user
        sql = """SELECT message_id FROM qiita.message_user
                 WHERE email = '*****@*****.**'"""
        m_id = get_count('qiita.message')
        self.assertEqual(self.conn_handler.execute_fetchall(sql), [[m_id]])
예제 #9
0
    def test_get_deselected(self):
        s = Study(1)
        u = User('*****@*****.**')
        args = {'deselected': u.id, 'id': s.id}
        self.assertEqual(s.shared_with, [u])
        response = self.get('/study/sharing/', args)
        self.assertEqual(response.code, 200)
        exp = {'users': [], 'links': ''}
        self.assertEqual(loads(response.body), exp)
        self.assertEqual(s.shared_with, [])

        # Make sure unshared message added to the system
        self.assertEqual('Study \'Identification of the Microbiomes for '
                         'Cannabis Soils\' has been unshared from you.',
                         u.messages()[0][1])
예제 #10
0
파일: test_user.py 프로젝트: adamrp/qiita
    def test_delete_messages(self):
        # Make message 1 a system message
        sql = """UPDATE qiita.message
                 SET expiration = '2015-08-05'
                 WHERE message_id = 1"""
        self.conn_handler.execute(sql)
        user = User('*****@*****.**')
        user.delete_messages([1, 2])
        obs = user.messages()
        exp_msg = [(3, 'message <a href="#">3</a>')]
        self.assertItemsEqual([(x[0], x[1]) for x in obs], exp_msg)

        sql = "SELECT message_id FROM qiita.message"
        obs = self.conn_handler.execute_fetchall(sql)
        self.assertItemsEqual(obs, [[1], [3]])
예제 #11
0
    def post(self):
        username = self.get_argument("email", "").strip().lower()
        password = self.get_argument("newpass", "")
        info = {}
        for info_column in ("name", "affiliation", "address", "phone"):
            hold = self.get_argument(info_column, None)
            if hold:
                info[info_column] = hold

        created = False
        try:
            created = User.create(username, password, info)
        except QiitaDBDuplicateError:
            msg = "Email already registered as a user"

        if created:
            info = created.info
            try:
                send_email(username, "QIITA: Verify Email Address", "Please "
                           "click the following link to verify email address: "
                           "%s/auth/verify/%s?email=%s"
                           % (qiita_config.base_url, info['user_verify_code'],
                              url_escape(username)))
            except:
                msg = ("Unable to send verification email. Please contact the "
                       "qiita developers at <a href='mailto:qiita-help"
                       "@gmail.com'>[email protected]</a>")
                self.redirect(u"/?level=danger&message=" + url_escape(msg))
                return
            self.redirect(u"/")
        else:
            error_msg = u"?error=" + url_escape(msg)
            self.redirect(u"/auth/create/" + error_msg)
예제 #12
0
    def post(self):
        username = self.get_argument("username", "").strip().lower()
        passwd = self.get_argument("password", "")
        nextpage = self.get_argument("next", "/")
        msg = ""
        # check the user level
        try:
            if User(username).level == "unverified":
                # email not verified so dont log in
                msg = "Email not verified"
        except QiitaDBUnknownIDError:
            msg = "Unknown user"

        # Check the login information
        login = None
        try:
            login = User.login(username, passwd)
        except IncorrectEmailError:
            msg = "Unknown user"
        except IncorrectPasswordError:
            msg = "Incorrect password"

        if login:
            # everything good so log in
            self.set_current_user(username)
            self.redirect(nextpage)
        else:
            self.render("index.html", user=None, loginerror=msg)
예제 #13
0
    def test_get_deselected(self):
        a = Analysis(1)
        u = User('*****@*****.**')
        args = {'deselected': u.id, 'id': a.id}
        self.assertEqual(a.shared_with, [u])
        response = self.get('/analysis/sharing/', args)
        self.assertEqual(response.code, 200)
        exp = {'users': [], 'links': ''}
        self.assertEqual(loads(response.body), exp)
        self.assertEqual(a.shared_with, [])

        # Make sure unshared message added to the system
        self.assertEqual('Analysis \'SomeAnalysis\' has been unshared from '
                         'you.', u.messages()[0][1])
        # Share the analysis back with the user
        a.share(u)
예제 #14
0
    def post(self, code):
        error = ""
        try:
            user = User(self.get_argument("email"))
        except QiitaDBUnknownIDError:
            error = "Unable to reset password"
        else:
            newpass = self.get_argument("newpass")
            changed = user.change_forgot_password(code, newpass)
            if changed:
                error = "Password reset successful. Please log in to continue."
            else:
                error = "Unable to reset password"

        self.render("change_lost_pass.html", user=None,
                    error=error, code=code)
예제 #15
0
 def get(self, code):
     email = self.get_argument("email").strip().lower()
     if User.verify_code(email, code, "create"):
         msg = "Successfully verified user! You are now free to log in."
     else:
         msg = "Code not valid!"
     self.render("user_verified.html", msg=msg)
예제 #16
0
파일: test_user.py 프로젝트: mortonjt/qiita
    def test_create_user(self):
        user = User.create('*****@*****.**', 'password')
        self.assertEqual(user.id, '*****@*****.**')
        sql = "SELECT * from qiita.qiita_user WHERE email = '*****@*****.**'"
        obs = self.conn_handler.execute_fetchall(sql)
        self.assertEqual(len(obs), 1)
        obs = dict(obs[0])
        exp = {
            'password': '',
            'name': None,
            'pass_reset_timestamp': None,
            'affiliation': None,
            'pass_reset_code': None,
            'phone': None,
            'user_verify_code': '',
            'address': None,
            'user_level_id': 5,
            'email': '*****@*****.**'}
        self._check_correct_info(obs, exp)

        # make sure default analysis created
        sql = ("SELECT email, name, description, dflt FROM qiita.analysis "
               "WHERE email = '*****@*****.**'")
        obs = self.conn_handler.execute_fetchall(sql)
        exp = [['*****@*****.**', '[email protected]', 'dflt', True]]
        self.assertEqual(obs, exp)
예제 #17
0
    def post(self):
        username = self.get_argument("username", "")
        passwd = self.get_argument("password", "")
        # check the user level
        try:
            if User(username).level == 4:  # 4 is id for unverified
                # email not verified so dont log in
                msg = "Email not verified"
        except QiitaDBUnknownIDError:
            msg = "Unknown user"

        # Check the login information
        login = None
        try:
            login = User.login(username, passwd)
        except IncorrectEmailError:
            msg = "Unknown user"
        except IncorrectPasswordError:
            msg = "Incorrect password"

        if login:
            # everthing good so log in
            self.set_current_user(username)
            self.redirect("/")
            return
        self.render("index.html", user=None, loginerror=msg)
예제 #18
0
    def test_get_selected(self):
        s = Analysis(1)
        u = User('*****@*****.**')
        args = {'selected': u.id, 'id': s.id}
        response = self.get('/analysis/sharing/', args)
        self.assertEqual(response.code, 200)
        exp = {
            'users': ['*****@*****.**', u.id],
            'links':
                ('<a target="_blank" href="mailto:[email protected]">Shared</a>, '
                 '<a target="_blank" href="mailto:[email protected]">Admin</a>')}
        self.assertEqual(loads(response.body), exp)
        self.assertEqual(s.shared_with, [User('*****@*****.**'), u])

        # Make sure shared message added to the system
        self.assertEqual('Analysis <a href="/analysis/results/1">'
                         '\'SomeAnalysis\'</a> has been shared with you.',
                         u.messages()[0][1])
예제 #19
0
    def test_get_selected(self):
        s = Study(1)
        u = User('*****@*****.**')
        args = {'selected': u.id, 'id': s.id}
        response = self.get('/study/sharing/', args)
        self.assertEqual(response.code, 200)
        exp = {
            'users': ['*****@*****.**', u.id],
            'links':
                ('<a target="_blank" href="mailto:[email protected]">Shared</a>, '
                 '<a target="_blank" href="mailto:[email protected]">Admin</a>')}
        self.assertEqual(loads(response.body), exp)
        self.assertEqual(s.shared_with, [User('*****@*****.**'), u])

        # Make sure shared message added to the system
        self.assertEqual('Study <a href="/study/description/1">'
                         '\'Identification of the Microbiomes for Cannabis '
                         'Soils\'</a> has been shared with you.',
                         u.messages()[0][1])
예제 #20
0
    def post(self):
        passmsg = ""
        msg = ""
        user = User(self.current_user)
        action = self.get_argument("action")
        if action == "profile":
            # tuple of colmns available for profile
            # FORM INPUT NAMES MUST MATCH DB COLUMN NAMES
            form_data = UserProfile()
            form_data.process(data=self.request.arguments)
            profile = {name: data[0] for name, data in
                       viewitems(form_data.data)}

            # Turn default value as list into default strings
            for field in form_data:
                field.data = field.data[0]
            try:
                user.info = profile
                msg = "Profile updated successfully"
            except Exception as e:
                msg = "ERROR: profile could not be updated"
                LogEntry.create('Runtime', "Cound not update profile: %s" %
                                str(e), info={'User': user.id})

        elif action == "password":
            form_data = UserProfile()
            form_data.process(data=user.info)
            oldpass = self.get_argument("oldpass")
            newpass = self.get_argument("newpass")
            try:
                changed = user.change_password(oldpass, newpass)
            except Exception as e:
                passmsg = "ERROR: could not change password"
                LogEntry.create('Runtime', "Could not change password: %s" %
                                str(e), info={'User': user.id})
            else:
                if changed:
                    passmsg = "Password changed successfully"
                else:
                    passmsg = "Incorrect old password"
        self.render("user_profile.html", user=user.id, profile=form_data,
                    msg=msg, passmsg=passmsg)
예제 #21
0
 def get(self, code):
     email = self.get_argument("email").strip().lower()
     if User.verify_code(email, code, "create"):
         msg = "Successfully verified user! You are now free to log in."
         color = "black"
         r_client.zadd('qiita-usernames', email, 0)
     else:
         msg = "Code not valid!"
         color = "red"
     self.render("user_verified.html", msg=msg, color=color,
                 email=self.get_argument("email").strip())
예제 #22
0
 def post(self):
     error = ""
     try:
         user = User(self.get_argument("email"))
     except QiitaDBUnknownIDError:
         error = "ERROR: Unknown user."
     else:
         user.generate_reset_code()
         info = user.info
         try:
             send_email(user, "QIITA: Password Reset", "Please go to the "
                        "following URL to reset your password: "******"http://qiita.colorado.edu/auth/reset/%s" %
                        info["pass_reset_code"])
             error = "Password reset. Check your email for the reset code."
         except Exception as e:
             error = "Unable to send email."
             LogEntry.create('Runtime', "Unable to send forgot password "
                             "email" % str(e), info={'User': user.id})
     self.render("lost_pass.html", user=None, error=error)
예제 #23
0
    def test_get(self):
        a = Analysis(1)
        u = User('*****@*****.**')
        self.assertEqual(a.shared_with, [u])

        # deselecting
        args = {'deselected': u.id, 'id': a.id}
        response = self.get('/analysis/sharing/', args)
        self.assertEqual(response.code, 200)
        exp = {'users': [], 'links': ''}
        self.assertEqual(loads(response.body), exp)
        self.assertEqual(a.shared_with, [])

        # Make sure unshared message added to the system
        self.assertEqual("Analysis 'SomeAnalysis' has been unshared with you.",
                         u.messages()[0][1])

        # selecting
        args = {'selected': u.id, 'id': a.id}
        response = self.get('/analysis/sharing/', args)
        self.assertEqual(response.code, 200)
        exp = {
            'users': ['*****@*****.**'],
            'links':
                ('<a target="_blank" href="mailto:[email protected]">Shared</a>')}
        self.assertEqual(loads(response.body), exp)
        self.assertEqual(a.shared_with, [u])

        # Make sure shared message added to the system
        self.assertEqual(
            'Analysis <a href="/analysis/description/1/">\'SomeAnalysis\'</a> '
            'has been shared with you.', u.messages()[0][1])

        # admins can share
        BaseHandler.get_current_user = Mock(return_value=User("*****@*****.**"))
        args = {'deselected': u.id, 'id': a.id}
        response = self.get('/analysis/sharing/', args)
        self.assertEqual(response.code, 200)
        exp = {'users': [], 'links': ''}
        self.assertEqual(loads(response.body), exp)
        self.assertEqual(a.shared_with, [])
예제 #24
0
 def test_generate_reset_code(self):
     user = User.create('*****@*****.**', 'password')
     sql = "SELECT LOCALTIMESTAMP"
     before = self.conn_handler.execute_fetchone(sql)[0]
     user.generate_reset_code()
     after = self.conn_handler.execute_fetchone(sql)[0]
     sql = ("SELECT pass_reset_code, pass_reset_timestamp FROM "
            "qiita.qiita_user WHERE email = %s")
     obscode, obstime = self.conn_handler.execute_fetchone(
         sql, ('*****@*****.**',))
     self.assertEqual(len(obscode), 20)
     self.assertTrue(before < obstime < after)
예제 #25
0
파일: test_user.py 프로젝트: mortonjt/qiita
    def setUp(self):
        self.user = User('*****@*****.**')

        self.userinfo = {
            'name': 'Dude',
            'affiliation': 'Nowhere University',
            'address': '123 fake st, Apt 0, Faketown, CO 80302',
            'phone': '111-222-3344',
            'pass_reset_code': None,
            'pass_reset_timestamp': None,
            'user_verify_code': None
        }
예제 #26
0
    def post(self):
        username = self.get_argument("email", "").strip().lower()
        password = self.get_argument("newpass", "")
        info = {}
        for info_column in ("name", "affiliation", "address", "phone"):
            hold = self.get_argument(info_column, None)
            if hold:
                info[info_column] = hold

        created = False
        try:
            created = User.create(username, password, info)
        except QiitaDBDuplicateError:
            msg = "Email already registered as a user"

        if created:
            info = created.info
            try:
                # qiita_config.base_url doesn't have a / at the end, but the
                # qiita_config.portal_dir has it at the beginning but not at
                # the end. This constructs the correct URL
                url = qiita_config.base_url + qiita_config.portal_dir
                send_email(username, "QIITA: Verify Email Address", "Please "
                           "click the following link to verify email address: "
                           "%s/auth/verify/%s?email=%s\n\nBy clicking you are "
                           "accepting our term and conditions: "
                           "%s/iframe/?iframe=qiita-terms"
                           % (url, info['user_verify_code'],
                              url_escape(username), url))
            except Exception:
                msg = ("Unable to send verification email. Please contact the "
                       "qiita developers at <a href='mailto:qiita-help"
                       "@gmail.com'>[email protected]</a>")
                self.redirect(u"%s/?level=danger&message=%s"
                              % (qiita_config.portal_dir, url_escape(msg)))
                return

            msg = ("<h3>User Successfully Created</h3><p>Your Qiita account "
                   "has been successfully created. An email has been sent to "
                   "the email address you provided. This email contains "
                   "instructions on how to activate your account.</p>"
                   "<p>If you don't receive your activation email within a "
                   "couple of minutes, check your spam folder. If you still "
                   "don't see it, send us an email at <a "
                   "href=\"mailto:[email protected]\">[email protected]"
                   "</a>.</p>")
            self.redirect(u"%s/?level=success&message=%s" %
                          (qiita_config.portal_dir, url_escape(msg)))
        else:
            error_msg = u"?error=" + url_escape(msg)
            self.redirect(u"%s/auth/create/%s"
                          % (qiita_config.portal_dir, error_msg))
예제 #27
0
파일: test_user.py 프로젝트: adamrp/qiita
    def test_mark_messages(self):
        user = User('*****@*****.**')
        user.mark_messages([1, 2])
        obs = user.messages()
        exp = [True, True, False]
        self.assertEqual([x[3] for x in obs], exp)

        user.mark_messages([1], read=False)
        obs = user.messages()
        exp = [False, True, False]
        self.assertEqual([x[3] for x in obs], exp)
예제 #28
0
    def post(self):
        if r_client.get('maintenance') is not None:
            raise HTTPError(503, "Site is down for maintenance")

        username = self.get_argument("username", "").strip().lower()
        passwd = self.get_argument("password", "")
        nextpage = self.get_argument("next", None)
        if nextpage is None:
            if "auth/" not in self.request.headers['Referer']:
                nextpage = self.request.headers['Referer']
            else:
                nextpage = "%s/" % qiita_config.portal_dir

        msg = ""
        # check the user level
        try:
            if User(username).level == "unverified":
                # email not verified so dont log in
                msg = ("Email not verified. Please check your email and click "
                       "the verify link. You may need to check your spam "
                       "folder to find the email.<br/>If a verification email"
                       " has not arrived in 15 minutes, please email <a href='"
                       "mailto:[email protected]'>[email protected]</a>")
        except QiitaDBUnknownIDError:
            msg = "Unknown user"
        except RuntimeError:
            # means DB not available, so set maintenance mode and failover
            r_client.set("maintenance", "Database connection unavailable, "
                         "please try again later.")
            self.redirect("%s/" % qiita_config.portal_dir)
            return

        # Check the login information
        login = None
        try:
            login = User.login(username, passwd)
        except IncorrectEmailError:
            msg = "Unknown user"
        except IncorrectPasswordError:
            msg = "Incorrect password"
        except UnverifiedEmailError:
            msg = "You have not verified your email address"

        if login:
            # everything good so log in
            self.set_current_user(username)
            self.redirect(nextpage)
        else:
            self.render("index.html", message=msg, level='danger')
예제 #29
0
    def post(self):
        if r_client.get('maintenance') is not None:
            raise HTTPError(503, "Site is down for maintenance")

        username = self.get_argument("username", "").strip().lower()
        passwd = self.get_argument("password", "")
        nextpage = self.get_argument("next", None)
        if nextpage is None:
            if "auth/" not in self.request.headers['Referer']:
                nextpage = self.request.headers['Referer']
            else:
                nextpage = "/"

        msg = ""
        # check the user level
        try:
            if User(username).level == "unverified":
                # email not verified so dont log in
                msg = "Email not verified"
        except QiitaDBUnknownIDError:
            msg = "Unknown user"
        except RuntimeError:
            # means DB not available, so set maintenance mode and failover
            r_client.set("maintenance", "Database connection unavailable, "
                         "please try again later.")
            self.redirect("/")
            return

        # Check the login information
        login = None
        try:
            login = User.login(username, passwd)
        except IncorrectEmailError:
            msg = "Unknown user"
        except IncorrectPasswordError:
            msg = "Incorrect password"
        except UnverifiedEmailError:
            msg = "You have not verified your email address"

        if login:
            # everything good so log in
            self.set_current_user(username)
            self.redirect(nextpage)
        else:
            self.render("index.html", message=msg, level='danger')
예제 #30
0
 def test_create_user_info(self):
     user = User.create('*****@*****.**', 'password', self.userinfo)
     self.assertEqual(user.id, '*****@*****.**')
     sql = "SELECT * from qiita.qiita_user WHERE email = '*****@*****.**'"
     obs = self.conn_handler.execute_fetchall(sql)
     self.assertEqual(len(obs), 1)
     obs = dict(obs[0])
     exp = {
         'password': '',
         'name': 'Dude',
         'affiliation': 'Nowhere University',
         'address': '123 fake st, Apt 0, Faketown, CO 80302',
         'phone': '111-222-3344',
         'pass_reset_timestamp': None,
         'pass_reset_code': None,
         'user_verify_code': '',
         'user_level_id': 5,
         'email': '*****@*****.**'}
     self._check_correct_info(obs, exp)
예제 #31
0
 def _unshare(self, study, user, callback):
     user = User(user)
     add_message('Study \'%s\' has been unshared from you.' %
                 study.title, [user])
     callback(study.unshare(user))
예제 #32
0
 def test_get_shared_studies(self):
     user = User('*****@*****.**')
     self.assertEqual(user.shared_studies, [1])
예제 #33
0
class UserTest(TestCase):
    """Tests the User object and all properties/methods"""
    def setUp(self):
        self.user = User('*****@*****.**')

        self.userinfo = {
            'name': 'Dude',
            'affiliation': 'Nowhere University',
            'address': '123 fake st, Apt 0, Faketown, CO 80302',
            'phone': '111-222-3344',
            'pass_reset_code': None,
            'pass_reset_timestamp': None,
            'user_verify_code': None
        }

    def test_instantiate_user(self):
        User('*****@*****.**')

    def test_instantiate_unknown_user(self):
        with self.assertRaises(QiitaDBUnknownIDError):
            User('*****@*****.**')

    def _check_correct_info(self, obs, exp):
        self.assertEqual(set(exp.keys()), set(obs.keys()))
        for key in exp:
            # user_verify_code and password seed randomly generated so just
            # making sure they exist and is correct length
            if key == 'user_verify_code':
                self.assertEqual(len(obs[key]), 20)
            elif key == "password":
                self.assertEqual(len(obs[key]), 60)
            else:
                self.assertEqual(obs[key], exp[key])

    def test_create_user(self):
        user = User.create('*****@*****.**', 'password')
        self.assertEqual(user.id, '*****@*****.**')
        sql = "SELECT * from qiita.qiita_user WHERE email = '*****@*****.**'"
        obs = self.conn_handler.execute_fetchall(sql)
        self.assertEqual(len(obs), 1)
        obs = dict(obs[0])
        exp = {
            'password': '',
            'name': None,
            'pass_reset_timestamp': None,
            'affiliation': None,
            'pass_reset_code': None,
            'phone': None,
            'user_verify_code': '',
            'address': None,
            'user_level_id': 5,
            'email': '*****@*****.**'
        }
        self._check_correct_info(obs, exp)

    def test_create_user_info(self):
        user = User.create('*****@*****.**', 'password', self.userinfo)
        self.assertEqual(user.id, '*****@*****.**')
        sql = "SELECT * from qiita.qiita_user WHERE email = '*****@*****.**'"
        obs = self.conn_handler.execute_fetchall(sql)
        self.assertEqual(len(obs), 1)
        obs = dict(obs[0])
        exp = {
            'password': '',
            'name': 'Dude',
            'affiliation': 'Nowhere University',
            'address': '123 fake st, Apt 0, Faketown, CO 80302',
            'phone': '111-222-3344',
            'pass_reset_timestamp': None,
            'pass_reset_code': None,
            'user_verify_code': '',
            'user_level_id': 5,
            'email': '*****@*****.**'
        }
        self._check_correct_info(obs, exp)

    def test_create_user_column_not_allowed(self):
        self.userinfo["email"] = "FAIL"
        with self.assertRaises(QiitaDBColumnError):
            User.create('*****@*****.**', 'password', self.userinfo)

    def test_create_user_non_existent_column(self):
        self.userinfo["BADTHING"] = "FAIL"
        with self.assertRaises(QiitaDBColumnError):
            User.create('*****@*****.**', 'password', self.userinfo)

    def test_create_user_duplicate(self):
        with self.assertRaises(QiitaDBDuplicateError):
            User.create('*****@*****.**', 'password')

    def test_create_user_bad_email(self):
        with self.assertRaises(IncorrectEmailError):
            User.create('notanemail', 'password')

    def test_create_user_bad_password(self):
        with self.assertRaises(IncorrectPasswordError):
            User.create('*****@*****.**', '')

    def test_login(self):
        self.assertEqual(User.login("*****@*****.**", "password"),
                         User("*****@*****.**"))

    def test_login_incorrect_user(self):
        with self.assertRaises(IncorrectEmailError):
            User.login("*****@*****.**", "password")

    def test_login_incorrect_password(self):
        with self.assertRaises(IncorrectPasswordError):
            User.login("*****@*****.**", "WRONGPASSWORD")

    def test_login_invalid_password(self):
        with self.assertRaises(IncorrectPasswordError):
            User.login("*****@*****.**", "SHORT")

    def test_exists(self):
        self.assertTrue(User.exists("*****@*****.**"))

    def test_exists_notindb(self):
        self.assertFalse(User.exists("*****@*****.**"))

    def test_exists_invaid_email(self):
        with self.assertRaises(IncorrectEmailError):
            User.exists("notanemail@badformat")

    def test_get_email(self):
        self.assertEqual(self.user.email, '*****@*****.**')

    def test_get_level(self):
        self.assertEqual(self.user.level, "admin")

    def test_get_info(self):
        expinfo = {
            'name': 'Admin',
            'affiliation': 'Owner University',
            'address': '312 noname st, Apt K, Nonexistantown, CO 80302',
            'phone': '222-444-6789',
            'pass_reset_code': None,
            'pass_reset_timestamp': None,
            'user_verify_code': None,
            'phone': '222-444-6789'
        }
        self.assertEqual(self.user.info, expinfo)

    def test_set_info(self):
        self.user.info = self.userinfo
        self.assertEqual(self.user.info, self.userinfo)

    def test_set_info_not_info(self):
        """Tests setting info with a non-allowed column"""
        self.userinfo["email"] = "FAIL"
        with self.assertRaises(QiitaDBColumnError):
            self.user.info = self.userinfo

    def test_set_info_bad_info(self):
        """Test setting info with a key not in the table"""
        self.userinfo["BADTHING"] = "FAIL"
        with self.assertRaises(QiitaDBColumnError):
            self.user.info = self.userinfo

    def test_get_user_studies(self):
        user = User('*****@*****.**')
        self.assertEqual(user.user_studies, [1])

    def test_get_shared_studies(self):
        user = User('*****@*****.**')
        self.assertEqual(user.shared_studies, [1])

    def test_get_private_analyses(self):
        self.assertEqual(self.user.private_analyses, [])

    def test_get_shared_analyses(self):
        self.assertEqual(self.user.shared_analyses, [])

    def test_verify_code(self):
        sql = ("insert into qiita.qiita_user values ('*****@*****.**', '1', "
               "'testtest', 'testuser', '', '', '', 'verifycode', 'resetcode'"
               ",null)")
        self.conn_handler.execute(sql)
        self.assertTrue(
            User.verify_code('*****@*****.**', 'verifycode', 'create'))
        self.assertTrue(User.verify_code('*****@*****.**', 'resetcode',
                                         'reset'))
        self.assertFalse(
            User.verify_code('*****@*****.**', 'wrongcode', 'create'))
        self.assertFalse(
            User.verify_code('*****@*****.**', 'wrongcode', 'reset'))
        with self.assertRaises(IncompetentQiitaDeveloperError):
            User.verify_code('*****@*****.**', 'fakecode', 'badtype')

    def _check_pass(self, passwd):
        obspass = self.conn_handler.execute_fetchone(
            "SELECT password FROM qiita.qiita_user WHERE email = %s",
            (self.user.id, ))[0]
        self.assertEqual(hash_password(passwd, obspass), obspass)

    def test_change_pass(self):
        self.user._change_pass("newpassword")
        self._check_pass("newpassword")
        self.assertIsNone(self.user.info["pass_reset_code"])

    def test_change_pass_short(self):
        with self.assertRaises(IncorrectPasswordError):
            self.user._change_pass("newpass")
        self._check_pass("password")

    def test_change_password(self):
        self.user.change_password("password", "newpassword")
        self._check_pass("newpassword")

    def test_change_password_wrong_oldpass(self):
        self.user.change_password("WRONG", "newpass")
        self._check_pass("password")

    def test_generate_reset_code(self):
        user = User.create('*****@*****.**', 'password')
        sql = "SELECT LOCALTIMESTAMP"
        before = self.conn_handler.execute_fetchone(sql)[0]
        user.generate_reset_code()
        after = self.conn_handler.execute_fetchone(sql)[0]
        sql = ("SELECT pass_reset_code, pass_reset_timestamp FROM "
               "qiita.qiita_user WHERE email = %s")
        obscode, obstime = self.conn_handler.execute_fetchone(
            sql, ('*****@*****.**', ))
        self.assertEqual(len(obscode), 20)
        self.assertTrue(before < obstime < after)

    def test_change_forgot_password(self):
        self.user.generate_reset_code()
        code = self.user.info["pass_reset_code"]
        obsbool = self.user.change_forgot_password(code, "newpassword")
        self.assertEqual(obsbool, True)
        self._check_pass("newpassword")

    def test_change_forgot_password_bad_code(self):
        self.user.generate_reset_code()
        code = "AAAAAAA"
        obsbool = self.user.change_forgot_password(code, "newpassword")
        self.assertEqual(obsbool, False)
        self._check_pass("password")
예제 #34
0
 def _unshare(self, analysis, user, callback):
     user = User(user)
     add_message(
         'Analysis \'%s\' has been unshared with you.' % analysis.name,
         [user])
     callback(analysis.unshare(user))
예제 #35
0
 def test_has_access_public(self):
     self.conn_handler.execute("UPDATE qiita.analysis SET "
                               "analysis_status_id = 6")
     self.assertTrue(self.analysis.has_access(User("*****@*****.**")))
예제 #36
0
 def test_retrieve_biom_tables_none(self):
     new = Analysis.create(User("*****@*****.**"), "newAnalysis",
                           "A New Analysis", Analysis(1))
     self.assertEqual(new.biom_tables, None)
예제 #37
0
    def test_retrieve_dropped_samples(self):
        # Create and populate second study to do test with
        info = {
            "timeseries_type_id": 1,
            "metadata_complete": True,
            "mixs_compliant": True,
            "number_samples_collected": 25,
            "number_samples_promised": 28,
            "portal_type_id": 3,
            "study_alias": "FCM",
            "study_description": "Microbiome of people who eat nothing but "
            "fried chicken",
            "study_abstract": "Exploring how a high fat diet changes the "
            "gut microbiome",
            "emp_person_id": StudyPerson(2),
            "principal_investigator_id": StudyPerson(3),
            "lab_person_id": StudyPerson(1)
        }
        metadata_dict = {
            'SKB8.640193': {
                'physical_location': 'location1',
                'has_physical_specimen': True,
                'has_extracted_data': True,
                'sample_type': 'type1',
                'required_sample_info_status': 'received',
                'collection_timestamp': datetime(2014, 5, 29, 12, 24, 51),
                'host_subject_id': 'NotIdentified',
                'Description': 'Test Sample 1',
                'str_column': 'Value for sample 1',
                'latitude': 42.42,
                'longitude': 41.41
            },
            'SKD8.640184': {
                'physical_location': 'location1',
                'has_physical_specimen': True,
                'has_extracted_data': True,
                'sample_type': 'type1',
                'required_sample_info_status': 'received',
                'collection_timestamp': datetime(2014, 5, 29, 12, 24, 51),
                'host_subject_id': 'NotIdentified',
                'Description': 'Test Sample 2',
                'str_column': 'Value for sample 2',
                'latitude': 4.2,
                'longitude': 1.1
            },
            'SKB7.640196': {
                'physical_location': 'location1',
                'has_physical_specimen': True,
                'has_extracted_data': True,
                'sample_type': 'type1',
                'required_sample_info_status': 'received',
                'collection_timestamp': datetime(2014, 5, 29, 12, 24, 51),
                'host_subject_id': 'NotIdentified',
                'Description': 'Test Sample 3',
                'str_column': 'Value for sample 3',
                'latitude': 4.8,
                'longitude': 4.41
            },
        }
        metadata = pd.DataFrame.from_dict(metadata_dict, orient='index')

        Study.create(User("*****@*****.**"), "Test study 2", [1], info)

        SampleTemplate.create(metadata, Study(2))

        mp = get_mountpoint("processed_data")[0][1]
        study_fp = join(mp, "2_study_1001_closed_reference_otu_table.biom")
        ProcessedData.create("processed_params_uclust",
                             1, [(study_fp, 6)],
                             study=Study(2),
                             data_type="16S")
        self.conn_handler.execute(
            "INSERT INTO qiita.analysis_sample (analysis_id, "
            "processed_data_id, sample_id) VALUES "
            "(1,2,'2.SKB8.640193'), (1,2,'2.SKD8.640184'), "
            "(1,2,'2.SKB7.640196')")

        samples = {
            1: ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196'],
            2: ['2.SKB8.640193', '2.SKD8.640184']
        }
        self.analysis._build_biom_tables(samples,
                                         10000,
                                         conn_handler=self.conn_handler)
        exp = {1: {'1.SKM4.640180', '1.SKM9.640192'}, 2: {'2.SKB7.640196'}}
        self.assertEqual(self.analysis.dropped_samples, exp)
예제 #38
0
파일: study.py 프로젝트: mestaki/qiita
    def post(self):
        try:
            payload = json_decode(self.request.body)
        except ValueError:
            self.fail('Could not parse body', 400)
            return

        required = {
            'title', 'study_abstract', 'study_description', 'study_alias',
            'owner', 'contacts'
        }

        if not required.issubset(payload):
            self.fail('Not all required arguments provided', 400)
            return

        title = payload['title']
        study_abstract = payload['study_abstract']
        study_desc = payload['study_description']
        study_alias = payload['study_alias']
        notes = payload['notes']

        owner = payload['owner']
        if not User.exists(owner):
            self.fail('Unknown user', 403)
            return
        else:
            owner = User(owner)

        contacts = payload['contacts']

        if Study.exists(title):
            self.fail('Study title already exists', 409)
            return

        pi_name = contacts['principal_investigator'][0]
        pi_aff = contacts['principal_investigator'][1]
        if not StudyPerson.exists(pi_name, pi_aff):
            self.fail('Unknown principal investigator', 403)
            return
        else:
            pi = StudyPerson.from_name_and_affiliation(pi_name, pi_aff)

        lp_name = contacts['lab_person'][0]
        lp_aff = contacts['lab_person'][1]
        if not StudyPerson.exists(lp_name, lp_aff):
            self.fail('Unknown lab person', 403)
            return
        else:
            lp = StudyPerson.from_name_and_affiliation(lp_name, lp_aff)

        info = {
            'lab_person_id': lp,
            'principal_investigator_id': pi,
            'study_abstract': study_abstract,
            'study_description': study_desc,
            'study_alias': study_alias,
            'notes': notes,
            # TODO: we believe it is accurate that mixs is false and
            # metadata completion is false as these cannot be known
            # at study creation here no matter what.
            # we do not know what should be done with the timeseries.
            'mixs_compliant': False,
            'metadata_complete': False,
            'timeseries_type_id': 1
        }
        study = Study.create(owner, title, info)

        self.set_status(201)
        self.write({'id': study.id})
        self.finish()
예제 #39
0
 def test_get(self):
     BaseHandler.get_current_user = Mock(return_value=User("*****@*****.**"))
     Artifact(4).visibility = "awaiting_approval"
     response = self.get('/admin/approval/')
     self.assertEqual(response.code, 200)
     self.assertIn("*****@*****.**", response.body)
예제 #40
0
    def test_artifact_patch_request(self):
        a = Artifact(1)
        test_user = User('*****@*****.**')
        self.assertEqual(a.name, 'Raw data 1')

        artifact_patch_request(test_user,
                               1,
                               'replace',
                               '/name/',
                               req_value='NEW_NAME')
        self.assertEqual(a.name, 'NEW_NAME')

        # Reset the name
        a.name = 'Raw data 1'

        # No access
        with self.assertRaises(QiitaHTTPError):
            artifact_patch_request(User('*****@*****.**'),
                                   1,
                                   'replace',
                                   '/name/',
                                   req_value='NEW_NAME')

        # Incorrect path parameter
        with self.assertRaises(QiitaHTTPError):
            artifact_patch_request(test_user,
                                   1,
                                   'replace',
                                   '/name/wrong/',
                                   req_value='NEW_NAME')

        # Missing value
        with self.assertRaises(QiitaHTTPError):
            artifact_patch_request(test_user, 1, 'replace', '/name/')

        # Wrong attribute
        with self.assertRaises(QiitaHTTPError):
            artifact_patch_request(test_user,
                                   1,
                                   'replace',
                                   '/wrong/',
                                   req_value='NEW_NAME')

        # Wrong operation
        with self.assertRaises(QiitaHTTPError):
            artifact_patch_request(test_user,
                                   1,
                                   'add',
                                   '/name/',
                                   req_value='NEW_NAME')

        # Changing visibility
        self.assertEqual(a.visibility, 'private')
        artifact_patch_request(test_user,
                               1,
                               'replace',
                               '/visibility/',
                               req_value='sandbox')
        self.assertEqual(a.visibility, 'sandbox')

        # Admin can change to private
        artifact_patch_request(User('*****@*****.**'),
                               1,
                               'replace',
                               '/visibility/',
                               req_value='private')
        self.assertEqual(a.visibility, 'private')

        # Test user can't change to private
        with self.assertRaises(QiitaHTTPError):
            artifact_patch_request(test_user,
                                   1,
                                   'replace',
                                   '/visibility/',
                                   req_value='private')

        # Unkown req value
        with self.assertRaises(QiitaHTTPError):
            artifact_patch_request(test_user,
                                   1,
                                   'replace',
                                   '/visibility/',
                                   req_value='wrong')
예제 #41
0
    def test_artifact_summary_get_request(self):
        user = User('*****@*****.**')
        # Artifact w/o summary
        obs = artifact_summary_get_request(user, 1)
        exp_p_jobs = [[
            '063e553b-327c-4818-ab4a-adfe58e49860', 'Split libraries FASTQ',
            'queued', None, None
        ],
                      [
                          'bcc7ebcd-39c1-43e4-af2d-822e3589f14d',
                          'Split libraries', 'running', 'demultiplexing', None
                      ]]
        exp_files = [
            (1L, '1_s_G1_L001_sequences.fastq.gz (raw forward seqs)'),
            (2L, '1_s_G1_L001_sequences_barcodes.fastq.gz (raw barcodes)')
        ]
        exp = {
            'name':
            'Raw data 1',
            'artifact_id':
            1,
            'artifact_type':
            'FASTQ',
            'artifact_timestamp':
            '2012-10-01 09:10',
            'visibility':
            'private',
            'editable':
            True,
            'buttons': ('<button onclick="if (confirm(\'Are you sure you '
                        'want to make public artifact id: 1?\')) { '
                        'set_artifact_visibility(\'public\', 1) }" '
                        'class="btn btn-primary btn-sm">Make public'
                        '</button> <button onclick="if (confirm(\'Are you '
                        'sure you want to revert to sandbox artifact id: '
                        '1?\')) { set_artifact_visibility(\'sandbox\', 1) '
                        '}" class="btn btn-primary btn-sm">Revert to '
                        'sandbox</button>'),
            'processing_parameters': {},
            'files':
            exp_files,
            'is_from_analysis':
            False,
            'summary':
            None,
            'job':
            None,
            'processing_jobs':
            exp_p_jobs,
            'errored_jobs': []
        }
        self.assertEqual(obs, exp)

        # Artifact with summary being generated
        job = ProcessingJob.create(
            User('*****@*****.**'),
            Parameters.load(Command(7), values_dict={'input_data': 1}))
        job._set_status('queued')
        obs = artifact_summary_get_request(user, 1)
        exp = {
            'name':
            'Raw data 1',
            'artifact_id':
            1,
            'artifact_type':
            'FASTQ',
            'artifact_timestamp':
            '2012-10-01 09:10',
            'visibility':
            'private',
            'editable':
            True,
            'buttons': ('<button onclick="if (confirm(\'Are you sure you '
                        'want to make public artifact id: 1?\')) { '
                        'set_artifact_visibility(\'public\', 1) }" '
                        'class="btn btn-primary btn-sm">Make public'
                        '</button> <button onclick="if (confirm(\'Are you '
                        'sure you want to revert to sandbox artifact id: '
                        '1?\')) { set_artifact_visibility(\'sandbox\', 1) '
                        '}" class="btn btn-primary btn-sm">Revert to '
                        'sandbox</button>'),
            'processing_parameters': {},
            'files':
            exp_files,
            'is_from_analysis':
            False,
            'summary':
            None,
            'job': [job.id, 'queued', None],
            'processing_jobs':
            exp_p_jobs,
            'errored_jobs': []
        }
        self.assertEqual(obs, exp)

        # Artifact with summary
        fd, fp = mkstemp(suffix=".html")
        close(fd)
        with open(fp, 'w') as f:
            f.write('<b>HTML TEST - not important</b>\n')
        a = Artifact(1)
        a.set_html_summary(fp)
        self._files_to_remove.extend([fp, a.html_summary_fp[1]])
        exp_files.append(
            (a.html_summary_fp[0],
             '%s (html summary)' % basename(a.html_summary_fp[1])))
        exp_summary_path = relpath(a.html_summary_fp[1],
                                   qiita_config.base_data_dir)
        obs = artifact_summary_get_request(user, 1)
        exp = {
            'name':
            'Raw data 1',
            'artifact_id':
            1,
            'artifact_type':
            'FASTQ',
            'artifact_timestamp':
            '2012-10-01 09:10',
            'visibility':
            'private',
            'editable':
            True,
            'buttons': ('<button onclick="if (confirm(\'Are you sure you '
                        'want to make public artifact id: 1?\')) { '
                        'set_artifact_visibility(\'public\', 1) }" '
                        'class="btn btn-primary btn-sm">Make public'
                        '</button> <button onclick="if (confirm(\'Are you '
                        'sure you want to revert to sandbox artifact id: '
                        '1?\')) { set_artifact_visibility(\'sandbox\', 1) '
                        '}" class="btn btn-primary btn-sm">Revert to '
                        'sandbox</button>'),
            'processing_parameters': {},
            'files':
            exp_files,
            'is_from_analysis':
            False,
            'summary':
            exp_summary_path,
            'job':
            None,
            'processing_jobs':
            exp_p_jobs,
            'errored_jobs': []
        }
        self.assertEqual(obs, exp)

        # No access
        demo_u = User('*****@*****.**')
        with self.assertRaises(QiitaHTTPError):
            obs = artifact_summary_get_request(demo_u, 1)

        # A non-owner/share user can't see the files
        a.visibility = 'public'
        obs = artifact_summary_get_request(demo_u, 1)
        exp = {
            'name': 'Raw data 1',
            'artifact_id': 1,
            'artifact_type': 'FASTQ',
            'artifact_timestamp': '2012-10-01 09:10',
            'visibility': 'public',
            'editable': False,
            'buttons': '',
            'processing_parameters': {},
            'files': [],
            'is_from_analysis': False,
            'summary': exp_summary_path,
            'job': None,
            'processing_jobs': exp_p_jobs,
            'errored_jobs': []
        }
        self.assertEqual(obs, exp)

        # returnig to private
        a.visibility = 'private'

        # admin gets buttons
        obs = artifact_summary_get_request(User('*****@*****.**'), 2)
        exp_p_jobs = [[
            'd19f76ee-274e-4c1b-b3a2-a12d73507c55',
            'Pick closed-reference OTUs', 'error', 'generating demux file',
            'Error message'
        ]]
        exp_files = [(3L, '1_seqs.fna (preprocessed fasta)'),
                     (4L, '1_seqs.qual (preprocessed fastq)'),
                     (5L, '1_seqs.demux (preprocessed demux)')]
        exp = {
            'name':
            'Demultiplexed 1',
            'artifact_id':
            2,
            'artifact_type':
            'Demultiplexed',
            'artifact_timestamp':
            '2012-10-01 10:10',
            'visibility':
            'private',
            'editable':
            True,
            'buttons': ('<button onclick="if (confirm(\'Are you sure you '
                        'want to make public artifact id: 2?\')) { '
                        'set_artifact_visibility(\'public\', 2) }" '
                        'class="btn btn-primary btn-sm">Make public'
                        '</button> <button onclick="if (confirm(\'Are you '
                        'sure you want to revert to sandbox artifact id: '
                        '2?\')) { set_artifact_visibility(\'sandbox\', 2) '
                        '}" class="btn btn-primary btn-sm">Revert to '
                        'sandbox</button> <a class="btn btn-primary '
                        'btn-sm" href="/ebi_submission/2"><span '
                        'class="glyphicon glyphicon-export"></span> '
                        'Submit to EBI</a> <a class="btn btn-primary '
                        'btn-sm" href="/vamps/2"><span class="glyphicon '
                        'glyphicon-export"></span> Submit to VAMPS</a>'),
            'processing_parameters': {
                'max_barcode_errors': 1.5,
                'sequence_max_n': 0,
                'max_bad_run_length': 3,
                'phred_offset': u'auto',
                'rev_comp': False,
                'phred_quality_threshold': 3,
                'input_data': 1,
                'rev_comp_barcode': False,
                'rev_comp_mapping_barcodes': False,
                'min_per_read_length_fraction': 0.75,
                'barcode_type': u'golay_12'
            },
            'files':
            exp_files,
            'is_from_analysis':
            False,
            'summary':
            None,
            'job':
            None,
            'processing_jobs':
            exp_p_jobs,
            'errored_jobs': []
        }
        self.assertEqual(obs, exp)

        # analysis artifact
        obs = artifact_summary_get_request(user, 8)
        exp = {
            'name': 'noname',
            'artifact_id': 8,
            'artifact_type': 'BIOM',
            # this value changes on build so copy from obs
            'artifact_timestamp': obs['artifact_timestamp'],
            'visibility': 'sandbox',
            'editable': True,
            'buttons': '',
            'processing_parameters': {},
            'files': [(27, 'biom_table.biom (biom)')],
            'is_from_analysis': True,
            'summary': None,
            'job': None,
            'processing_jobs': [],
            'errored_jobs': []
        }
        self.assertEqual(obs, exp)
예제 #42
0
def sample_template_summary_get_req(samp_id, user_id):
    """Returns a summary of the sample template metadata columns

    Parameters
    ----------
    samp_id : int
        SampleTemplate id to get info for
    user_id : str
        User requesting the sample template info

    Returns
    -------
    dict
        Returns summary information in the form
        {'status': str,
         'message': str,
         'info': dict of {str: object}
        status can be success, warning, or error depending on result
        message has the warnings or errors
        info dictionary contains the keys as the metadata categories
        and the values are list of tuples. Each tuple is an observed value in
        the category and the number of times its seen.
        Format {num_samples: value,
                category: [(val1, count1), (val2, count2), ...], ...}
    """
    access_error = check_access(samp_id, user_id)
    if access_error:
        return access_error

    processing, alert_type, alert_msg = get_sample_template_processing_status(
        samp_id)

    exists = _check_sample_template_exists(int(samp_id))
    if exists['status'] != 'success':
        return {
            'status': 'success',
            'message': '',
            'num_samples': 0,
            'num_columns': 0,
            'editable': not processing,
            'alert_type': alert_type,
            'alert_message': alert_msg,
            'stats': {}
        }

    template = SampleTemplate(int(samp_id))

    df = template.to_dataframe()

    editable = (Study(template.study_id).can_edit(User(user_id))
                and not processing)

    out = {
        'status': 'success',
        'message': '',
        'num_samples': df.shape[0],
        'num_columns': df.shape[1],
        'editable': editable,
        'alert_type': alert_type,
        'alert_message': alert_msg,
        'stats': {}
    }

    # drop the samp_id column if it exists
    if 'study_id' in df.columns:
        df.drop('study_id', axis=1, inplace=True)
    for column in df.columns:
        counts = df[column].value_counts()
        out['stats'][str(column)] = [(str(key), counts[key])
                                     for key in natsorted(counts.index)]

    return out
예제 #43
0
 def test_unshare(self):
     self.collection.unshare(User("*****@*****.**"))
     obs = self.collection.shared_with
     exp = []
     self.assertEqual(obs, exp)
예제 #44
0
 def test_retrieve_step(self):
     new = Analysis.create(User("*****@*****.**"), "newAnalysis",
                           "A New Analysis", Analysis(1))
     new.step = 2
     self.assertEqual(new.step, 2)
예제 #45
0
    def test_complete_job(self):
        # Complete success
        pt = npt.assert_warns(QiitaDBWarning, PrepTemplate.create,
                              pd.DataFrame({'new_col': {
                                  '1.SKD6.640190': 1
                              }}), Study(1), '16S')
        c_job = ProcessingJob.create(
            User('*****@*****.**'),
            Parameters.load(Command.get_validator('BIOM'),
                            values_dict={
                                'template': pt.id,
                                'files': dumps({'BIOM': ['file']}),
                                'artifact_type': 'BIOM'
                            }), True)
        c_job._set_status('running')
        fd, fp = mkstemp(suffix='_table.biom')
        close(fd)
        with open(fp, 'w') as f:
            f.write('\n')
        self._clean_up_files.append(fp)
        exp_artifact_count = get_count('qiita.artifact') + 1
        payload = dumps({
            'success': True,
            'error': '',
            'artifacts': {
                'OTU table': {
                    'filepaths': [(fp, 'biom')],
                    'artifact_type': 'BIOM'
                }
            }
        })
        job = self._create_job('complete_job', {
            'job_id': c_job.id,
            'payload': payload
        })
        private_task(job.id)
        self.assertEqual(job.status, 'success')
        self.assertEqual(c_job.status, 'success')
        self.assertEqual(get_count('qiita.artifact'), exp_artifact_count)

        # Complete job error
        payload = dumps({'success': False, 'error': 'Job failure'})
        job = self._create_job('complete_job', {
            'job_id': 'bcc7ebcd-39c1-43e4-af2d-822e3589f14d',
            'payload': payload
        })
        private_task(job.id)
        self.assertEqual(job.status, 'success')
        c_job = ProcessingJob('bcc7ebcd-39c1-43e4-af2d-822e3589f14d')
        self.assertEqual(c_job.status, 'error')
        self.assertEqual(c_job.log, LogEntry.newest_records(numrecords=1)[0])
        self.assertEqual(c_job.log.msg, 'Job failure')

        # Complete internal error
        pt = npt.assert_warns(QiitaDBWarning, PrepTemplate.create,
                              pd.DataFrame({'new_col': {
                                  '1.SKD6.640190': 1
                              }}), Study(1), '16S')
        c_job = ProcessingJob.create(
            User('*****@*****.**'),
            Parameters.load(Command.get_validator('BIOM'),
                            values_dict={
                                'template': pt.id,
                                'files': dumps({'BIOM': ['file']}),
                                'artifact_type': 'BIOM'
                            }), True)
        c_job._set_status('running')
        fp = '/surprised/if/this/path/exists.biom'
        payload = dumps({
            'success': True,
            'error': '',
            'artifacts': {
                'OTU table': {
                    'filepaths': [(fp, 'biom')],
                    'artifact_type': 'BIOM'
                }
            }
        })
        job = self._create_job('complete_job', {
            'job_id': c_job.id,
            'payload': payload
        })
        private_task(job.id)
        self.assertEqual(job.status, 'success')
        self.assertEqual(c_job.status, 'error')
        self.assertIn('No such file or directory', c_job.log.msg)
예제 #46
0
 def test_retrieve_step_new(self):
     new = Analysis.create(User("*****@*****.**"), "newAnalysis",
                           "A New Analysis", Analysis(1))
     with self.assertRaises(ValueError):
         new.step
예제 #47
0
 def test_instantiate_unknown_user(self):
     with self.assertRaises(QiitaDBUnknownIDError):
         User('*****@*****.**')
예제 #48
0
 def test_retrieve_pmid_none(self):
     new = Analysis.create(User("*****@*****.**"), "newAnalysis",
                           "A New Analysis", Analysis(1))
     self.assertEqual(new.pmid, None)
예제 #49
0
 def test_instantiate_user(self):
     User('*****@*****.**')
예제 #50
0
 def test_retrieve_mapping_file_none(self):
     new = Analysis.create(User("*****@*****.**"), "newAnalysis",
                           "A New Analysis", Analysis(1))
     obs = new.mapping_file
     self.assertEqual(obs, None)
예제 #51
0
def prep_template_ajax_get_req(user_id, prep_id):
    """Returns the prep tempalte information needed for the AJAX handler

    Parameters
    ----------
    user_id : str
        The user id
    prep_id : int
        The prep template id

    Returns
    -------
    dict of {str: object}
        A dictionary with the following keys:
        - status: str, whether the request is successful or not
        - message: str, if the request is unsuccessful, a human readable error
        - name: str, the name of the prep template
        - files: list of str, the files available to update the prep template
        - download_prep: int, the filepath_id of the prep file
        - download_qiime, int, the filepath_id of the qiime mapping file
        - num_samples: int, the number of samples present in the template
        - num_columns: int, the number of columns present in the template
        - investigation_type: str, the investigation type of the template
        - ontology: str, dict of {str, list of str} containing the information
        of the ENA ontology
        - artifact_attached: bool, whether the template has an artifact
        attached
        - study_id: int, the study id of the template
    """
    pt = PrepTemplate(prep_id)
    name = pt.name

    # Initialize variables here
    processing = False
    alert_type = ''
    alert_msg = ''
    job_info = r_client.get(PREP_TEMPLATE_KEY_FORMAT % prep_id)
    if job_info:
        job_info = defaultdict(lambda: '', loads(job_info))
        job_id = job_info['job_id']
        job = ProcessingJob(job_id)
        job_status = job.status
        processing = job_status not in ('success', 'error')
        if processing:
            alert_type = 'info'
            alert_msg = 'This prep template is currently being updated'
        elif job_status == 'error':
            alert_type = 'danger'
            alert_msg = job.log.msg.replace('\n', '</br>')
        else:
            alert_type = job_info['alert_type']
            alert_msg = job_info['alert_msg'].replace('\n', '</br>')

    artifact_attached = pt.artifact is not None
    study_id = pt.study_id
    files = [
        f for _, f, _ in get_files_from_uploads_folders(study_id)
        if f.endswith(('.txt', '.tsv', '.xlsx'))
    ]

    # The call to list is needed because keys is an iterator
    num_samples = len(list(pt.keys()))
    num_columns = len(pt.categories())
    investigation_type = pt.investigation_type

    download_prep_id = None
    download_qiime_id = None
    other_filepaths = []
    for fp_id, fp in pt.get_filepaths():
        fp = basename(fp)
        if 'qiime' in fp:
            if download_qiime_id is None:
                download_qiime_id = fp_id
        else:
            if download_prep_id is None:
                download_prep_id = fp_id
            else:
                other_filepaths.append(fp)

    ontology = _get_ENA_ontology()

    editable = Study(study_id).can_edit(User(user_id)) and not processing

    success, restrictions = pt.validate_restrictions()

    return {
        'status': 'success',
        'message': '',
        'name': name,
        'files': files,
        'download_prep_id': download_prep_id,
        'download_qiime_id': download_qiime_id,
        'other_filepaths': other_filepaths,
        'num_samples': num_samples,
        'num_columns': num_columns,
        'investigation_type': investigation_type,
        'ontology': ontology,
        'artifact_attached': artifact_attached,
        'study_id': study_id,
        'editable': editable,
        'data_type': pt.data_type(),
        'alert_type': alert_type,
        'is_submitted_to_ebi': pt.is_submitted_to_ebi,
        'prep_restrictions': restrictions,
        'samples': sorted(list(pt.keys())),
        'alert_message': alert_msg
    }
예제 #52
0
 def _get_all_emails(self, callback):
     callback(list(User.iter()))
예제 #53
0
 def test_get_user_studies(self):
     user = User('*****@*****.**')
     self.assertEqual(user.user_studies, [1])
예제 #54
0
 def test_unshare(self):
     self.analysis.unshare(User("*****@*****.**"))
     self.assertEqual(self.analysis.shared_with, [])
예제 #55
0
 def _share(self, study, user, callback):
     user = User(user)
     add_message('Study <a href="%s/study/description/%d">\'%s\'</a> '
                 'has been shared with you.' %
                 (qiita_config.portal_dir, study.id, study.title), [user])
     callback(study.share(user))
예제 #56
0
 def test_share(self):
     self.collection.share(User("*****@*****.**"))
     obs = self.collection.shared_with
     exp = ["*****@*****.**", "*****@*****.**"]
     self.assertEqual(obs, exp)
예제 #57
0
 def test_add_samples(self):
     new = Analysis.create(User("*****@*****.**"), "newAnalysis",
                           "A New Analysis")
     new.add_samples([(1, '1.SKB8.640193'), (1, '1.SKD5.640186')])
     exp = {1: ['1.SKB8.640193', '1.SKD5.640186']}
     self.assertEqual(new.samples, exp)
예제 #58
0
def prep_template_patch_req(user_id,
                            req_op,
                            req_path,
                            req_value=None,
                            req_from=None):
    """Modifies an attribute of the prep template

    Parameters
    ----------
    user_id : str
        The id of the user performing the patch operation
    req_op : str
        The operation to perform on the prep information
    req_path : str
        The prep information and attribute to patch
    req_value : str, optional
        The value that needs to be modified
    req_from : str, optional
        The original path of the element

    Returns
    -------
    dict of {str, str, str}
        A dictionary with the following keys:
        - status: str, whether if the request is successful or not
        - message: str, if the request is unsuccessful, a human readable error
        - row_id: str, the row_id that we tried to delete
    """
    req_path = [v for v in req_path.split('/') if v]
    if req_op == 'replace':
        # The structure of the path should be /prep_id/attribute_to_modify/
        # so if we don't have those 2 elements, we should return an error
        if len(req_path) != 2:
            return {'status': 'error', 'message': 'Incorrect path parameter'}
        prep_id = int(req_path[0])
        attribute = req_path[1]

        # Check if the user actually has access to the prep template
        prep = PrepTemplate(prep_id)
        access_error = check_access(prep.study_id, user_id)
        if access_error:
            return access_error

        status = 'success'
        msg = ''
        if attribute == 'investigation_type':
            prep.investigation_type = req_value
        elif attribute == 'data':
            fp = check_fp(prep.study_id, req_value)
            if fp['status'] != 'success':
                return fp
            fp = fp['file']
            qiita_plugin = Software.from_name_and_version('Qiita', 'alpha')
            cmd = qiita_plugin.get_command('update_prep_template')
            params = Parameters.load(cmd,
                                     values_dict={
                                         'prep_template': prep_id,
                                         'template_fp': fp
                                     })
            job = ProcessingJob.create(User(user_id), params, True)

            r_client.set(PREP_TEMPLATE_KEY_FORMAT % prep_id,
                         dumps({'job_id': job.id}))
            job.submit()
        elif attribute == 'name':
            prep.name = req_value.strip()
        else:
            # We don't understand the attribute so return an error
            return {
                'status':
                'error',
                'message':
                'Attribute "%s" not found. '
                'Please, check the path parameter' % attribute
            }

        return {'status': status, 'message': msg}
    elif req_op == 'remove':
        # The structure of the path should be:
        # /prep_id/row_id/{columns|samples}/name
        if len(req_path) != 4:
            return {'status': 'error', 'message': 'Incorrect path parameter'}
        prep_id = int(req_path[0])
        row_id = req_path[1]
        attribute = req_path[2]
        attr_id = req_path[3]

        # Check if the user actually has access to the study
        pt = PrepTemplate(prep_id)
        access_error = check_access(pt.study_id, user_id)
        if access_error:
            return access_error

        qiita_plugin = Software.from_name_and_version('Qiita', 'alpha')
        cmd = qiita_plugin.get_command('delete_sample_or_column')
        params = Parameters.load(cmd,
                                 values_dict={
                                     'obj_class': 'PrepTemplate',
                                     'obj_id': prep_id,
                                     'sample_or_col': attribute,
                                     'name': attr_id
                                 })
        job = ProcessingJob.create(User(user_id), params, True)
        # Store the job id attaching it to the sample template id
        r_client.set(PREP_TEMPLATE_KEY_FORMAT % prep_id,
                     dumps({'job_id': job.id}))
        job.submit()
        return {'status': 'success', 'message': '', 'row_id': row_id}
    else:
        return {
            'status':
            'error',
            'message':
            'Operation "%s" not supported. '
            'Current supported operations: replace, remove' % req_op,
            'row_id':
            '0'
        }
예제 #59
0
 def test_share(self):
     self.analysis.share(User("*****@*****.**"))
     self.assertEqual(self.analysis.shared_with,
                      ["*****@*****.**", "*****@*****.**"])
예제 #60
0
def artifact_post_req(user_id,
                      filepaths,
                      artifact_type,
                      name,
                      prep_template_id,
                      artifact_id=None):
    """Creates the initial artifact for the prep template

    Parameters
    ----------
    user_id : str
        User adding the atrifact
    filepaths : dict of str
        Comma-separated list of files to attach to the artifact,
        keyed by file type
    artifact_type : str
        The type of the artifact
    name : str
        Name to give the artifact
    prep_template_id : int or str castable to int
        Prep template to attach the artifact to
    artifact_id : int or str castable to int, optional
        The id of the imported artifact

    Returns
    -------
    dict of objects
        A dictionary containing the new artifact ID
        {'status': status,
         'message': message,
         'artifact': id}
    """
    prep_template_id = int(prep_template_id)
    prep = PrepTemplate(prep_template_id)
    study_id = prep.study_id

    # First check if the user has access to the study
    access_error = check_access(study_id, user_id)
    if access_error:
        return access_error

    user = User(user_id)

    if artifact_id:
        # if the artifact id has been provided, import the artifact
        qiita_plugin = Software.from_name_and_version('Qiita', 'alpha')
        cmd = qiita_plugin.get_command('copy_artifact')
        params = Parameters.load(cmd,
                                 values_dict={
                                     'artifact': artifact_id,
                                     'prep_template': prep.id
                                 })
        job = ProcessingJob.create(user, params, True)
    else:
        uploads_path = get_mountpoint('uploads')[0][1]
        path_builder = partial(join, uploads_path, str(study_id))
        cleaned_filepaths = {}

        for ftype, file_list in viewitems(filepaths):
            # JavaScript sends us this list as a comma-separated list
            for fp in file_list.split(','):
                # JavaScript will send this value as an empty string if the
                # list of files was empty. In such case, the split will
                # generate a single element containing the empty string. Check
                # for that case here and, if fp is not the empty string,
                # proceed to check if the file exists
                if fp:
                    # Check if filepath being passed exists for study
                    full_fp = path_builder(fp)
                    exists = check_fp(study_id, full_fp)
                    if exists['status'] != 'success':
                        return {
                            'status': 'error',
                            'message': 'File does not exist: %s' % fp
                        }
                    if ftype not in cleaned_filepaths:
                        cleaned_filepaths[ftype] = []
                    cleaned_filepaths[ftype].append(full_fp)

        # This should never happen, but it doesn't hurt to actually have
        # a explicit check, in case there is something odd with the JS
        if not cleaned_filepaths:
            return {
                'status': 'error',
                'message': "Can't create artifact, no files provided."
            }

        command = Command.get_validator(artifact_type)
        job = ProcessingJob.create(
            user,
            Parameters.load(command,
                            values_dict={
                                'template': prep_template_id,
                                'files': dumps(cleaned_filepaths),
                                'artifact_type': artifact_type,
                                'name': name,
                                'analysis': None,
                            }), True)

    # Submit the job
    job.submit()

    r_client.set(PREP_TEMPLATE_KEY_FORMAT % prep.id,
                 dumps({
                     'job_id': job.id,
                     'is_qiita_job': True
                 }))

    return {'status': 'success', 'message': ''}