Repository: BrandonLMorris/auacm-cli

Issue:
List recent and ongoing competitions
A `comp[etition]` command that will simply list (chronologically) the recent and ongoing competitions.

Discussion:

Patch:
diff --git a/src/auacm/competition.py b/src/auacm/competition.py
index f2d9561..794f8a4 100644
--- a/src/auacm/competition.py
+++ b/src/auacm/competition.py
@@ -1,6 +1,6 @@
 """Subcommands related to competitions"""
 
-import auacm, requests, textwrap
+import auacm, requests, textwrap, argparse
 from datetime import datetime
 from auacm.utils import subcommand
 from auacm.exceptions import CompetitionNotFoundError
@@ -10,7 +10,7 @@ from auacm.exceptions import CompetitionNotFoundError
 def get_comps(args=None):
     """Retrieve one or more competitions from the server"""
     if args:
-        return _get_one_comp(args)
+        return get_one_comp(args)
 
     response = requests.get(auacm.BASE_URL + 'competitions')
 
@@ -35,13 +35,30 @@ def get_comps(args=None):
         {}
         ''').format(current, upcoming, past).strip()
 
-def _get_one_comp(args):
+def get_one_comp(args):
     """Retrieve info on one specific competition"""
-    response = requests.get(auacm.BASE_URL + 'competitions/' + str(args[0]))
+    parser = argparse.ArgumentParser(
+        add_help=False,
+        usage='competition [-i/--id] <competition>'
+    )
+    parser.add_argument('-i', '--id', action='store_true')
+    parser.add_argument('competition')
+    args = parser.parse_args(args)
+
+    if not args.id:
+        cid = _cid_from_name(args.competition)
+        if cid == -1:
+            raise CompetitionNotFoundError(
+                'Could not find a competition with the name ' +
+                args.competition)
+    else:
+        cid = args.competition
+
+    response = requests.get(auacm.BASE_URL + 'competitions/' + str(cid))
 
     if not response.ok or response.status_code == 404:
         raise CompetitionNotFoundError(
-            'Could not find competition with id: ' + str(args[0]))
+            'Could not find competition with id: ' + str(args.competition))
 
     comp = response.json()['data']
 
@@ -62,6 +79,21 @@ def _get_one_comp(args):
         {}
         ''').format(comp_str, teams, problems)
 
+def _cid_from_name(comp_name):
+    """Return the competition of an id based on it's name"""
+    comps = requests.get(auacm.BASE_URL + 'competitions').json()['data']
+    for comp in comps['upcoming']:
+        if comp_name.lower() in comp['name'].lower():
+            return int(comp['cid'])
+    for comp in comps['ongoing']:
+        if comp_name.lower() in comp['name'].lower():
+            return int(comp['cid'])
+    for comp in comps['past']:
+        if comp_name.lower() in comp['name'].lower():
+            return int(comp['cid'])
+
+    return -1
+
 def _format_comps(comps):
     """Return a formatted string for a list of competitions"""
     result = list()
@@ -85,7 +117,7 @@ def _format_teams(teams):
 def _format_problems(probs):
     """Return a formatted string of the problems passed in"""
     result = ''
-    for label, prob in probs.items():
+    for label, prob in sorted(probs.items()):
         result += '{}\t{} ({})\n'.format(label, prob['name'], prob['pid'])
     return result.strip()
 
diff --git a/src/auacm/main.py b/src/auacm/main.py
index 32d55e0..35e463b 100644
--- a/src/auacm/main.py
+++ b/src/auacm/main.py
@@ -7,7 +7,7 @@ The central entry point of the auacm app.
 import requests, sys, textwrap
 import auacm
 import auacm.utils as utils
-from auacm.exceptions import ConnectionError, ProblemNotFoundError, UnauthorizedException, InvalidSubmission
+from auacm.exceptions import ConnectionError, ProblemNotFoundError, UnauthorizedException, InvalidSubmission, CompetitionNotFoundError
 
 def main(args):
     """
@@ -44,7 +44,8 @@ def main(args):
             print(utils.callbacks[args[0]](args[1:]) or '')
         except (ProblemNotFoundError,
                 UnauthorizedException,
-                InvalidSubmission) as exp:
+                InvalidSubmission,
+                CompetitionNotFoundError) as exp:
             print(exp.message)
             exit(1)
         except (requests.exceptions.ConnectionError, ConnectionError):


Test patch:
diff --git a/tests/competition_tests.py b/tests/competition_tests.py
index 7f7c381..b89e62e 100644
--- a/tests/competition_tests.py
+++ b/tests/competition_tests.py
@@ -21,16 +21,38 @@ class CompetitionTests(unittest.TestCase):
         self.assertTrue('past fake mock' in result.lower())
 
     @patch('requests.get')
-    def testGetOneCompetition(self, mock_get):
-        """Successfully get one competition by it's id"""
+    def testGetOneCompetitionById(self, mock_get):
+        """Successfully get one competition by its id"""
         mock_get.return_value = MockResponse(json=COMPETITION_DETAIL)
 
-        result = auacm.competition.get_comps(['2'])
+        result = auacm.competition.get_comps(['-i', '2'])
 
         self.assertTrue('ongoing fake mock' in result.lower())
         self.assertTrue('fake problem a' in result.lower())
         self.assertTrue('brando the mando' in result.lower())
 
+    @patch('requests.get')
+    def testGetOneCompetitionByName(self, mock_get):
+        """Successfully get one competition by its name"""
+        mock_get.side_effect = [
+            MockResponse(json=COMPETITIONS_RESPONSE),
+            MockResponse(json=COMPETITION_DETAIL)]
+
+        result = auacm.competition.get_comps(['ongoing'])
+
+        self.assertTrue('ongoing fake mock' in result.lower())
+        self.assertTrue('fake problem a' in result.lower())
+        self.assertTrue('brando the mando' in result.lower())
+
+    @patch('requests.get')
+    def testGetOneCompetitionBadName(self, mock_get):
+        """Attempt to get a competition that doesn't exist by name"""
+        mock_get.side_effect = [
+            MockResponse(json=COMPETITIONS_RESPONSE)]
+
+        self.assertRaises(
+            auacm.exceptions.CompetitionNotFoundError,
+            auacm.competition.get_comps, ['not real'])
 
     @patch('requests.get')
     def testGetOneCompetitionBad(self, mock_get):
@@ -39,7 +61,7 @@ class CompetitionTests(unittest.TestCase):
 
         self.assertRaises(
             auacm.exceptions.CompetitionNotFoundError,
-            auacm.competition.get_comps, ['99999999'])
+            auacm.competition.get_comps, ['-i', '99999999'])
 
 
 if __name__ == '__main__':