Merge: lib/counter: Added pack function
authorJean Privat <jean@pryen.org>
Thu, 8 Dec 2016 21:58:38 +0000 (16:58 -0500)
committerJean Privat <jean@pryen.org>
Thu, 8 Dec 2016 21:58:38 +0000 (16:58 -0500)
Added Counter::pack to separate values by occurence into a final 2D array of values

Pull-Request: #2346

31 files changed:
lib/core/bytes.nit
lib/core/text/abstract_text.nit
lib/for_abuse.nit
lib/mongodb/mongodb.nit
lib/postgresql/postgres.nit
share/nitweb/directives/metrics/metrics_list.html
share/nitweb/directives/ui-summary.html [new file with mode: 0644]
share/nitweb/directives/user/sidebar.html [new file with mode: 0644]
share/nitweb/directives/user/user-menu.html
share/nitweb/index.html
share/nitweb/javascripts/nitweb.js
share/nitweb/javascripts/ui.js
share/nitweb/javascripts/users.js
share/nitweb/stylesheets/nitweb.css
share/nitweb/views/class.html
share/nitweb/views/group.html
share/nitweb/views/module.html
share/nitweb/views/package.html
share/nitweb/views/property.html
share/nitweb/views/user.html
src/doc/doc_down.nit
src/nitcatalog.nit
src/nitweb.nit
src/test_neo.nit
src/web/api_auth.nit [new file with mode: 0644]
src/web/web.nit
tests/sav/nitcatalog_args1.res
tests/test_neo4j.nit
tests/test_neo4j_batch.nit
tests/test_postgres_native.nit
tests/test_postgres_nity.nit

index 85b457f..9e7064a 100644 (file)
@@ -572,15 +572,16 @@ class Bytes
 
        # Decode `self` from percent (or URL) encoding to a clear string
        #
-       # Replace invalid use of '%' with '?'.
+       # Invalid '%' are not decoded.
        #
        #     assert "aBc09-._~".to_bytes.from_percent_encoding == "aBc09-._~".to_bytes
        #     assert "%25%28%29%3c%20%3e".to_bytes.from_percent_encoding == "%()< >".to_bytes
        #     assert ".com%2fpost%3fe%3dasdf%26f%3d123".to_bytes.from_percent_encoding == ".com/post?e=asdf&f=123".to_bytes
        #     assert "%25%28%29%3C%20%3E".to_bytes.from_percent_encoding == "%()< >".to_bytes
-       #     assert "incomplete %".to_bytes.from_percent_encoding == "incomplete ?".to_bytes
-       #     assert "invalid % usage".to_bytes.from_percent_encoding == "invalid ? usage".to_bytes
+       #     assert "incomplete %".to_bytes.from_percent_encoding == "incomplete %".to_bytes
+       #     assert "invalid % usage".to_bytes.from_percent_encoding == "invalid % usage".to_bytes
        #     assert "%c3%a9%e3%81%82%e3%81%84%e3%81%86".to_bytes.from_percent_encoding == "éあいう".to_bytes
+       #     assert "%1 %A %C3%A9A9".to_bytes.from_percent_encoding == "%1 %A éA9".to_bytes
        fun from_percent_encoding: Bytes do
                var tmp = new Bytes.with_capacity(length)
                var pos = 0
@@ -592,14 +593,14 @@ class Bytes
                                continue
                        end
                        if length - pos < 2 then
-                               tmp.add '?'.ascii
+                               tmp.add '%'.ascii
                                pos += 1
                                continue
                        end
                        var bn = self[pos + 1]
                        var bnn = self[pos + 2]
                        if not bn.is_valid_hexdigit or not bnn.is_valid_hexdigit then
-                               tmp.add '?'.ascii
+                               tmp.add '%'.ascii
                                pos += 1
                                continue
                        end
index f95377e..50f0aff 100644 (file)
@@ -843,15 +843,16 @@ abstract class Text
 
        # Decode `self` from percent (or URL) encoding to a clear string
        #
-       # Replace invalid use of '%' with '?'.
+       # Invalid '%' are not decoded.
        #
        #     assert "aBc09-._~".from_percent_encoding == "aBc09-._~"
        #     assert "%25%28%29%3c%20%3e".from_percent_encoding == "%()< >"
        #     assert ".com%2fpost%3fe%3dasdf%26f%3d123".from_percent_encoding == ".com/post?e=asdf&f=123"
        #     assert "%25%28%29%3C%20%3E".from_percent_encoding == "%()< >"
-       #     assert "incomplete %".from_percent_encoding == "incomplete ?"
-       #     assert "invalid % usage".from_percent_encoding == "invalid ? usage"
+       #     assert "incomplete %".from_percent_encoding == "incomplete %"
+       #     assert "invalid % usage".from_percent_encoding == "invalid % usage"
        #     assert "%c3%a9%e3%81%82%e3%81%84%e3%81%86".from_percent_encoding == "éあいう"
+       #     assert "%1 %A %C3%A9A9".from_percent_encoding == "%1 %A éA9"
        fun from_percent_encoding: String
        do
                var len = byte_length
@@ -874,7 +875,7 @@ abstract class Text
                        if c == '%' then
                                if i + 2 >= length then
                                        # What follows % has been cut off
-                                       buf[l] = '?'.ascii
+                                       buf[l] = '%'.ascii
                                else
                                        i += 1
                                        var hex_s = substring(i, 2)
@@ -884,7 +885,7 @@ abstract class Text
                                                i += 1
                                        else
                                                # What follows a % is not Hex
-                                               buf[l] = '?'.ascii
+                                               buf[l] = '%'.ascii
                                                i -= 1
                                        end
                                end
index 812fb02..f19bd0f 100644 (file)
@@ -8,7 +8,7 @@
 # You  are  allowed  to  redistribute it and sell it, alone or is a part of
 # another product.
 
-# Service management trough the `for` control structure.
+# Service management through the `for` control structure.
 #
 # The module is a proof-of-concept to investigate the abuse of
 # the `for` structure to implement various services.
@@ -135,7 +135,7 @@ private class SortAbuserIterator[E]
 end
 
 redef class Array[E]
-       # Sort an array trough a `for` abuse.
+       # Sort an array through a `for` abuse.
        # The user uses the provided query (item) to implements its own comparison
        #
        #     var a = [1, 3, 2]
@@ -151,7 +151,7 @@ end
 
 ####
 
-# Open and read a file trough a `for` abuse.
+# Open and read a file through a `for` abuse.
 # The abuse just ensures that the file is closed after the reading.
 #
 #     for f in file_open("/etc/issue") do
index 17b137f..3469976 100644 (file)
 # # Opens the connexion with the Mongo server.
 # var client = new MongoClient("mongodb://localhost:27017/")
 #
+# # Select the database.
+# var db_suffix = "NIT_TESTING_ID".environ
+# var db_name = "test_{db_suffix}"
+# var db = client.database(db_name)
+#
 # # Retrieve a collection.
-# var col = client.database("test").collection("test")
+# var col = db.collection("test")
 #
 # # Insert a document in the collection.
 # var doc = new JsonObject
@@ -226,7 +231,9 @@ class MongoClient
        #
        # ~~~
        # var client = new MongoClient("mongodb://localhost:27017/")
-       # var db = client.database("test")
+       # var db_suffix = "NIT_TESTING_ID".environ
+       # var db_name = "test_{db_suffix}"
+       # var db = client.database(db_name)
        # db.collection("test").insert(new JsonObject)
        # assert client.database_names.has("test")
        # ~~~
@@ -253,7 +260,10 @@ class MongoClient
        #
        # ~~~
        # var client = new MongoClient("mongodb://localhost:27017/")
-       # assert client.database("test").name == "test"
+       # var db_suffix = "NIT_TESTING_ID".environ
+       # var db_name = "test_{db_suffix}"
+       # var db = client.database(db_name)
+       # assert db.name == db_name
        # ~~~
        fun database(name: String): MongoDb do return new MongoDb(self, name)
 
@@ -312,7 +322,9 @@ class MongoDb
        #
        # ~~~
        # var client = new MongoClient("mongodb://localhost:27017/")
-       # var db = client.database("test")
+       # var db_suffix = "NIT_TESTING_ID".environ
+       # var db_name = "test_{db_suffix}"
+       # var db = client.database(db_name)
        # db.collection("test").insert(new JsonObject)
        # assert db.collection_names.has("test")
        # ~~~
@@ -335,7 +347,9 @@ class MongoDb
        #
        # ~~~
        # var client = new MongoClient("mongodb://localhost:27017/")
-       # var db = client.database("test")
+       # var db_suffix = "NIT_TESTING_ID".environ
+       # var db_name = "test_{db_suffix}"
+       # var db = client.database(db_name)
        # var col = db.collection("test")
        # assert col.name == "test"
        # ~~~
@@ -347,7 +361,9 @@ class MongoDb
        #
        # ~~~
        # var client = new MongoClient("mongodb://localhost:27017/")
-       # var db = client.database("test")
+       # var db_suffix = "NIT_TESTING_ID".environ
+       # var db_name = "test_{db_suffix}"
+       # var db = client.database(db_name)
        # assert not db.has_collection("qwerty")
        # ~~~
        fun has_collection(name: String): Bool do
@@ -405,7 +421,10 @@ class MongoCollection
        #
        # ~~~
        # var client = new MongoClient("mongodb://localhost:27017/")
-       # var col = client.database("test").collection("test")
+       # var db_suffix = "NIT_TESTING_ID".environ
+       # var db_name = "test_{db_suffix}"
+       # var db = client.database(db_name)
+       # var col = db.collection("test")
        # var doc = new JsonObject
        # doc["foo"] = 10
        # doc["bar"] = "bar"
@@ -437,7 +456,10 @@ class MongoCollection
        #
        # ~~~
        # var client = new MongoClient("mongodb://localhost:27017/")
-       # var col = client.database("test").collection("test")
+       # var db_suffix = "NIT_TESTING_ID".environ
+       # var db_name = "test_{db_suffix}"
+       # var db = client.database(db_name)
+       # var col = db.collection("test")
        #
        # var doc = new JsonObject
        # doc["foo"] = 10
@@ -467,7 +489,10 @@ class MongoCollection
        #
        # ~~~
        # var client = new MongoClient("mongodb://localhost:27017/")
-       # var col = client.database("test").collection("test")
+       # var db_suffix = "NIT_TESTING_ID".environ
+       # var db_name = "test_{db_suffix}"
+       # var db = client.database(db_name)
+       # var col = db.collection("test")
        # var sel = new JsonObject
        # sel["foo"] = 10
        # assert col.remove(sel)
@@ -489,7 +514,10 @@ class MongoCollection
        #
        # ~~~
        # var client = new MongoClient("mongodb://localhost:27017/")
-       # var col = client.database("test").collection("test")
+       # var db_suffix = "NIT_TESTING_ID".environ
+       # var db_name = "test_{db_suffix}"
+       # var db = client.database(db_name)
+       # var col = db.collection("test")
        # var sel = new JsonObject
        # sel["foo"] = 10
        # var upd = new JsonObject
@@ -517,7 +545,10 @@ class MongoCollection
        #
        # ~~~
        # var client = new MongoClient("mongodb://localhost:27017/")
-       # var col = client.database("test").collection("test")
+       # var db_suffix = "NIT_TESTING_ID".environ
+       # var db_name = "test_{db_suffix}"
+       # var db = client.database(db_name)
+       # var col = db.collection("test")
        # var query = new JsonObject
        # query["foo"] = 10
        # assert col.count(query) > 0
@@ -536,7 +567,10 @@ class MongoCollection
        #
        # ~~~
        # var client = new MongoClient("mongodb://localhost:27017/")
-       # var col = client.database("test").collection("test")
+       # var db_suffix = "NIT_TESTING_ID".environ
+       # var db_name = "test_{db_suffix}"
+       # var db = client.database(db_name)
+       # var col = db.collection("test")
        # var query = new JsonObject
        # query["foo"] = 10
        # var doc = col.find(query)
@@ -566,7 +600,10 @@ class MongoCollection
        #
        # ~~~
        # var client = new MongoClient("mongodb://localhost:27017/")
-       # var col = client.database("test").collection("test")
+       # var db_suffix = "NIT_TESTING_ID".environ
+       # var db_name = "test_{db_suffix}"
+       # var db = client.database(db_name)
+       # var col = db.collection("test")
        # var query = new JsonObject
        # query["foo"] = 10
        # assert col.find_all(query).length > 0
@@ -589,7 +626,10 @@ class MongoCollection
        #
        # ~~~
        # var client = new MongoClient("mongodb://localhost:27017/")
-       # var col = client.database("test").collection("test_aggregate")
+       # var db_suffix = "NIT_TESTING_ID".environ
+       # var db_name = "test_{db_suffix}"
+       # var db = client.database(db_name)
+       # var col = db.collection("test_aggregate")
        #
        # col.drop
        #
@@ -626,8 +666,11 @@ class MongoCollection
        #
        # ~~~
        # var client = new MongoClient("mongodb://localhost:27017/")
-       # var col = client.database("test").collection("test")
-       # assert col.stats["ns"] == "test.test"
+       # var db_suffix = "NIT_TESTING_ID".environ
+       # var db_name = "test_{db_suffix}"
+       # var db = client.database(db_name)
+       # var col = db.collection("test")
+       # assert col.stats["ns"] == "{db_name}.test"
        # ~~~
        fun stats: nullable JsonObject do
                var bson = native.stats
index 22e498f..d8a475e 100644 (file)
 # animals.add(cat)
 # animals.add(turtle)
 #
+# var db_suffix = "NIT_TESTING_ID".environ
 # var db = new Postgres.open("dbname=postgres")
 #
 # assert db_is_open: not db.is_closed
-# assert create_table: db.create_table("IF NOT EXISTS animals (aname TEXT PRIMARY KEY, kind TEXT NOT NULL, age INT NOT NULL)") else print db.error
+# assert create_table: db.create_table("IF NOT EXISTS animals_{db_suffix} (aname TEXT PRIMARY KEY, kind TEXT NOT NULL, age INT NOT NULL)") else print db.error
 #
 # for animal in animals do
-#   assert insert: db.insert("INTO animals VALUES('{animal.name}', '{animal.kind}', {animal.age})") else print db.error
+#   assert insert: db.insert("INTO animals_{db_suffix} VALUES('{animal.name}', '{animal.kind}', {animal.age})") else print db.error
 # end
 #
-# var result = db.raw_execute("SELECT * FROM animals")
+# var result = db.raw_execute("SELECT * FROM animals_{db_suffix}")
 # assert  result.is_ok
-# assert drop_table: db.execute("DROP TABLE animals")
+# assert drop_table: db.execute("DROP TABLE animals_{db_suffix}")
 # db.finish
 # assert db_is_closed: db.is_closed
 # ~~~
@@ -59,6 +60,7 @@ private import native_postgres
 class Postgres
   private var native_connection: NativePostgres
 
+  # Is the connection closed?
   var is_closed = true
 
   # Open the connnection with the database using the `conninfo`
@@ -78,8 +80,22 @@ class Postgres
     native_connection.finish
   end
 
+  # Prepares the statement `query` with `stmt_name` to be executed later
+  #
+  # `num_params` specifies the number of parameters expected at the statement
+  # execution.
+  #
+  # See `exec_prepared` for execution.
   fun prepare(stmt_name:String, query:String, num_params: Int):PGResult do return new PGResult(native_connection.prepare(stmt_name, query, num_params))
 
+  # Execute prepared statement named `stmt_name` with `values`
+  #
+  # * `num_params` specifies the number of parameters given to the prepared statement
+  # * `param_lengths` specifies the length of each parameters
+  # * `param_formats` and `result_format` specifies the format used as input/output.
+  #   Should be 0 for text results, 1 for binary.
+  #
+  # See `prepare`.
   fun exec_prepared(stmt_name: String, num_params: Int, values: Array[String], param_lengths: Array[Int], param_formats: Array[Int], result_format: Int):PGResult do
     return new PGResult(native_connection.exec_prepared(stmt_name, num_params, values, param_lengths, param_formats, result_format))
   end
@@ -119,6 +135,7 @@ end
 class PGResult
   private var pg_result: NativePGResult
 
+  # Clears the result object and frees the memory allocated to the underlying C struct
   fun clear do pg_result.clear
 
   # Returns the number of rows in the query result
index 7351363..1a1916b 100644 (file)
@@ -1,8 +1,6 @@
 <div class='card'>
        <div class='card-body'>
-               <div class='card-heading'>
-                       <h4 class='card-title'>{{listTitle}}</h4>
-               </div>
+               <h4 class='card-heading'>{{listTitle}}</h4>
                <table class='table'>
                        <tr>
                                <th></th>
diff --git a/share/nitweb/directives/ui-summary.html b/share/nitweb/directives/ui-summary.html
new file mode 100644 (file)
index 0000000..3edf99d
--- /dev/null
@@ -0,0 +1,23 @@
+<div>
+       <h4>Summary</h4>
+       <div ng-repeat='entry in headings' class='summary'>
+               <h1 ng-if='entry.level == 1'>
+                       <a ng-click='goTo(entry)'>{{entry.text}}</a>
+               </h1>
+               <h2 ng-if='entry.level == 2'>
+                       <a ng-click='goTo(entry)'>{{entry.text}}</a>
+               </h2>
+               <h3 ng-if='entry.level == 3'>
+                       <a ng-click='goTo(entry)'>{{entry.text}}</a>
+               </h3>
+               <h4 ng-if='entry.level == 4'>
+                       <a ng-click='goTo(entry)'>{{entry.text}}</a>
+               </h4>
+               <h5 ng-if='entry.level == 5'>
+                       <a ng-click='goTo(entry)'>{{entry.text}}</a>
+               </h5>
+               <h6 ng-if='entry.level == 6'>
+                       <a ng-click='goTo(entry)'>{{entry.text}}</a>
+               </h6>
+       </div>
+</div>
diff --git a/share/nitweb/directives/user/sidebar.html b/share/nitweb/directives/user/sidebar.html
new file mode 100644 (file)
index 0000000..8a546f9
--- /dev/null
@@ -0,0 +1,15 @@
+<div>
+       <img class='avatar' width='100%' src='{{user.avatar_url}}' />
+       <h1>{{user.login}}</h1>
+       <h3>{{user.name}}</h3>
+       <ul class='list-unstyled'>
+               <li>
+                       <span class='glyphicon glyphicon-envelope' />
+                       <a href='mailto:{{user.email}}'>{{user.email}}</a>
+               </li>
+               <li>
+                       <span class='glyphicon glyphicon-link' />
+                       <a href='{{user.blog}}'>{{user.blog}}</a>
+               </li>
+       </ul>
+</div>
index 8d1f7bf..cc77885 100644 (file)
                        <img class='avatar avatar-icon' ng-src='{{user.avatar_url}}' />
                </a>
                <ul class="dropdown-menu dropdown-menu-right">
-                       <li><a href="/user">Profile</a></li>
+                       <li>
+                               <a href="/user"><span class='glyphicon glyphicon-user' /> Profile</a>
+                       </li>
                        <li role="separator" class="divider"></li>
-                       <li><a href="/logout">Logout</a></li>
+                       <li>
+                               <a href="/logout"><span class='glyphicon glyphicon-log-out' /> Logout</a>
+                       </li>
                </ul>
        </li>
 </ul>
index 930931d..1117ae7 100644 (file)
@@ -34,8 +34,8 @@
                                                                <span class='glyphicon glyphicon-menu-hamburger' />
                                                        </a>
                                                        <ul class='dropdown-menu'>
-                                                               <li><a href='/docdown'>DocDown</a></li>
-                                                               <li><a href='/grades'>Grades</a></li>
+                                                               <li><a href='/docdown?edit'><span class='glyphicon glyphicon-edit'></span> DocDown</a></li>
+                                                               <li><a href='/grades'><span class='glyphicon glyphicon-stats'></span> Grades</a></li>
                                                        </ul>
                                                </li>
                                        </ul>
@@ -77,8 +77,7 @@
                </script>
                <script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular-sanitize.js'>
                </script>
-               <script type='text/javascript'
-                       src='//cdnjs.cloudflare.com/ajax/libs/angular-loading-bar/0.9.0/loading-bar.min.js'>
+               <script src='//cdnjs.cloudflare.com/ajax/libs/angular-loading-bar/0.9.0/loading-bar.min.js'>
                </script>
 
                <script src='/javascripts/nitweb.js'></script>
index 803b84b..78f0f71 100644 (file)
@@ -56,7 +56,8 @@
                        .when('/doc/:id', {
                                templateUrl: 'views/doc.html',
                                controller: 'EntityCtrl',
-                               controllerAs: 'entityCtrl'
+                               controllerAs: 'entityCtrl',
+                               reloadOnSearch: false
                        })
                        .otherwise({
                                templateUrl: 'views/error.html'
index f33a439..e9f91d2 100644 (file)
                        };
                })
 
+               .directive('uiSummary', function($rootScope, $location, $anchorScroll) {
+                       return {
+                               restrict: 'E',
+                               scope: {
+                                       target: '@'
+                               },
+                               replace: true,
+                               templateUrl: '/directives/ui-summary.html',
+                               link: function ($scope, element, attrs) {
+                                       $scope.goTo = function(entity) {
+                                               $location.hash(entity.id);
+                                       }
+
+                                       $scope.textToId = function(text) {
+                                               return text.replace(/ /g, '-').replace(/[^A-Za-z_-]/g, '');
+                                       }
+
+                                       $rootScope.reloadSummary = function() {
+                                               var h = angular.element(document.querySelectorAll(
+                                                       $scope.target + ' h1, ' +
+                                                       $scope.target + ' h2, ' +
+                                                       $scope.target + ' h3, ' +
+                                                       $scope.target + ' h4, ' +
+                                                       $scope.target + ' h5, ' +
+                                                       $scope.target + ' h6 '));
+
+                                               $scope.headings = [];
+                                               angular.forEach(h, function(heading) {
+                                                       var head = angular.element(heading);
+                                                       if(!head.is(':visible')) { return ; }
+                                                       var text = head.text().trim();
+                                                       var id = $scope.textToId(text);
+                                                       if(!head.attr('id')) {
+                                                               head.attr('id', id);
+                                                       } else {
+                                                               id = head.attr('id');
+                                                       }
+                                                       $scope.headings.push({
+                                                               id: id,
+                                                               text: text,
+                                                               level: parseInt(head[0].nodeName[1])
+                                                       });
+                                               });
+                                               $anchorScroll();
+                                       }
+
+                                       $scope.$watch('target', function() {
+                                               setTimeout(function() {
+                                                       $rootScope.reloadSummary();
+                                               }, 100);
+                                       });
+                               }
+                       };
+               })
+
                .directive('uiFilterForm', function() {
                        return {
                                restrict: 'E',
index b9c077a..bd446b7 100644 (file)
@@ -39,7 +39,7 @@
                        this.loadGrades();
                }])
 
-               .directive('userMenu', ['User', function(User) {
+               .directive('userMenu', ['User', '$rootScope', function(User, $rootScope) {
                        return {
                                restrict: 'E',
                                templateUrl: '/directives/user/user-menu.html',
@@ -47,7 +47,7 @@
                                        $scope.loadUser = function() {
                                                User.loadUser(
                                                        function(data) {
-                                                               $scope.user = data;
+                                                               $rootScope.user = data;
                                                        }, function(err) {
                                                                //$scope.error = err;
                                                        });
                                }
                        };
                }])
+
+               .directive('userSidebar', ['User', '$rootScope', function(User, $rootScope) {
+                       return {
+                               restrict: 'E',
+                               templateUrl: '/directives/user/sidebar.html',
+                       };
+               }])
 })();
index ca15a6f..b78f244 100644 (file)
@@ -94,7 +94,7 @@ entity-list:hover .btn-filter {
 /* doc */
 
 .nitdoc .synopsys {
-       font-size: 2em;
+       margin-top: 0;
 }
 
 .signature {
@@ -224,6 +224,23 @@ entity-list:hover .btn-filter {
        margin-bottom: 0px;
 }
 
+/* Summary */
+
+.summary h1, .summary h2, .summary h3, .summary h4, .summary h5, .summary h6 {
+       margin: 5px 0;
+}
+
+.summary h1 a, .summary h2 a, .summary h3 a, .summary h4 a, .summary h5 a, .summary h6 a {
+       color: #555;
+}
+
+.summary h1 { font-size: 14px; margin-left: 0px; font-weight: bold; }
+.summary h2 { font-size: 13px; margin-left: 5px; font-weight: bold; }
+.summary h3 { font-size: 12px; margin-left: 10px; }
+.summary h4 { font-size: 11px; margin-left: 15px; }
+.summary h5 { font-size: 10px; margin-left: 20px; }
+.summary h6 { font-size: 9px; margin-left: 25px; }
+
 /*
  * Ratings
  */
index 445ef37..278e676 100644 (file)
 
 <div class='tab-content'>
        <div role='tabpanel' class='tab-pane fade in active' id='doc'>
-               <entity-card mentity='mentity' default-tab='doc' no-synopsis='true' />
+               <div class='col-xs-3'>
+                       <ui-summary target='#summary-content' />
+               </div>
+               <div id='summary-content' class='col-xs-9'>
+                       <entity-card mentity='mentity' default-tab='doc' no-synopsis='true' />
 
-               <entity-list list-title='Parents'
-                       list-entities='mentity.parents'
-                       list-object-filter='{}' />
+                       <entity-list list-title='Parents'
+                               list-entities='mentity.parents'
+                               list-object-filter='{}' />
 
-               <entity-list list-title='Constructors'
-                       list-entities='mentity.all_mproperties'
-                       list-object-filter='{is_init: true}' />
+                       <entity-list list-title='Constructors'
+                               list-entities='mentity.all_mproperties'
+                               list-object-filter='{is_init: true}' />
 
-               <entity-list list-title='Introduced properties'
-                       list-entities='mentity.intro_mproperties'
-                       list-object-filter='{is_init: "!true"}' />
+                       <entity-list list-title='Introduced properties'
+                               list-entities='mentity.intro_mproperties'
+                               list-object-filter='{is_init: "!true"}' />
 
-               <entity-list list-title='Redefined properties'
-                       list-entities='mentity.redef_mproperties'
-                       list-object-filter='{is_init: "!true"}' />
+                       <entity-list list-title='Redefined properties'
+                               list-entities='mentity.redef_mproperties'
+                               list-object-filter='{is_init: "!true"}' />
+               </div>
        </div>
        <div role='tabpanel' class='tab-pane fade' id='all_props'>
                <entity-list list-title='All properties' list-entities='mentity.all_mproperties'
        </div>
        <div role='tabpanel' class='tab-pane fade' id='metrics'>
                <div class='card'>
-                       <div class='card-heading'>
-                               <h3 class='card-title'>Class inheritance</h3>
-                       </div>
                        <div class='card-body container-fluid'>
+                               <h3 class='card-heading'>Class inheritance</h3>
                                <div class='col-sm-6'>
                                        <h4>
                                                Inheritance kind
                        </div>
                </div>
                <div class='card'>
-                       <div class='card-heading'>
-                               <h3 class='card-title'>Class properties</h3>
-                       </div>
                        <div class='card-body container-fluid'>
+                               <h3 class='card-heading'>Class properties</h3>
                                <div class='col-sm-6'>
                                        <h4>
                                                Properties kind
index 46a2c51..0f7347b 100644 (file)
 
 <div class='tab-content'>
        <div role='tabpanel' class='tab-pane fade in active' id='doc'>
-               <entity-card mentity='mentity' default-tab='doc' no-synopsis='true' />
+               <div class='col-xs-3'>
+                       <ui-summary target='#summary-content' />
+               </div>
+               <div class='col-xs-9' id='summary-content'>
+                       <entity-card mentity='mentity' default-tab='doc' no-synopsis='true' />
 
-               <entity-list list-title='Parent group' list-entities='[mentity.parent]'
-                       list-object-filter='{}' ng-if='mentity.parent' />
+                       <entity-list list-title='Parent group' list-entities='[mentity.parent]'
+                               list-object-filter='{}' ng-if='mentity.parent' />
 
-               <entity-list list-title='Subgroups' list-entities='mentity.mgroups'
-                       list-object-filter='{}' />
+                       <entity-list list-title='Subgroups' list-entities='mentity.mgroups'
+                               list-object-filter='{}' />
 
-               <entity-list list-title='Modules' list-entities='mentity.mmodules'
-                       list-object-filter='{}' />
+                       <entity-list list-title='Modules' list-entities='mentity.mmodules'
+                               list-object-filter='{}' />
+               </div>
        </div>
        <div role='tabpanel' class='tab-pane fade' id='graph'>
                <div class='card'>
index 92ec2f9..3891267 100644 (file)
 
 <div class='tab-content'>
        <div role='tabpanel' class='tab-pane fade in active' id='doc'>
-               <entity-card mentity='mentity' default-tab='doc' no-synopsis='true' />
-
-               <entity-list list-title='Imported modules' list-entities='mentity.imports'
-                       list-object-filter='{}' />
+               <div class='col-xs-3'>
+                       <ui-summary target='#summary-content' />
+               </div>
+               <div class='col-xs-9' id='summary-content'>
+                       <entity-card mentity='mentity' default-tab='doc' no-synopsis='true' />
 
-               <entity-list list-title='Introduced classes' list-entities='mentity.intro_mclasses'
-                       list-object-filter='{}' />
+                       <entity-list list-title='Imported modules' list-entities='mentity.imports'
+                               list-object-filter='{}' />
 
-               <entity-list list-title='Class redefinitions' list-entities='mentity.redef_mclassdefs'
-                       list-object-filter='{}' />
+                       <entity-list list-title='Introduced classes' list-entities='mentity.intro_mclasses'
+                               list-object-filter='{}' />
 
+                       <entity-list list-title='Class redefinitions' list-entities='mentity.redef_mclassdefs'
+                               list-object-filter='{}' />
+               </div>
        </div>
        <div role='tabpanel' class='tab-pane fade' id='code'>
                <div class='card'>
        </div>
        <div role='tabpanel' class='tab-pane fade' id='metrics'>
                <div class='card'>
-                       <div class='card-heading'>
-                               <h3 class='card-title'>Module importation</h3>
-                       </div>
                        <div class='card-body container-fluid'>
+                               <h3 class='card-heading'>Module importation</h3>
                                <div class='col-sm-6'>
                                        <h4>
                                                Importation metrics
                        </div>
                </div>
                <div class='card'>
-                       <div class='card-heading'>
-                               <h3 class='card-title'>Module definitions</h3>
-                       </div>
                        <div class='card-body container-fluid'>
+                               <h3 class='card-heading'>Module definitions</h3>
                                <div class='col-sm-6'>
                                        <h4>
                                                Class definition kinds
index 33b360b..38b1bf6 100644 (file)
 
 <div class='tab-content'>
        <div role='tabpanel' class='tab-pane fade in active' id='doc'>
-               <entity-card mentity='mentity' default-tab='doc' no-synopsis='true' />
+               <div class='col-xs-3'>
+                       <ui-summary target='#summary-content' />
+               </div>
+               <div class='col-xs-9' id='summary-content'>
+                       <entity-card mentity='mentity' default-tab='doc' no-synopsis='true' />
 
-               <entity-list list-title='Groups' list-entities='mentity.mgroups'
-                       list-object-filter='{}' />
+                       <entity-list list-title='Groups' list-entities='mentity.mgroups'
+                               list-object-filter='{}' />
+               </div>
        </div>
        <div role='tabpanel' class='tab-pane fade' id='graph'>
                <div class='card'>
index a3c2281..345a3bf 100644 (file)
 
 <div class='tab-content'>
        <div role='tabpanel' class='tab-pane fade in active' id='doc'>
-               <entity-card mentity='mentity' default-tab='doc' no-synopsis='true' />
+               <div class='col-xs-3'>
+                       <ui-summary target='#summary-content' />
+               </div>
+               <div class='col-xs-9' id='summary-content'>
+                       <entity-card mentity='mentity' default-tab='doc' no-synopsis='true' />
+               </div>
        </div>
        <div role='tabpanel' class='tab-pane fade' id='linearization'>
                <entity-linearization
index c9f10f5..b1d947c 100644 (file)
@@ -1,18 +1,6 @@
-<div class='container'>
-       <div class='col-xs-4'>
-               <img class='avatar' width='100%' src='{{user.avatar_url}}' />
-               <h1>{{user.login}}</h1>
-               <h3>{{user.name}}</h3>
-               <ul class='list-unstyled'>
-                       <li>
-                               <span class='glyphicon glyphicon-envelope' />
-                               <a href='mailto:{{user.email}}'>{{user.email}}</a>
-                       </li>
-                       <li>
-                               <span class='glyphicon glyphicon-link' />
-                               <a href='{{user.blog}}'>{{user.blog}}</a>
-                       </li>
-               </ul>
+<div class='container-fluid'>
+       <div class='col-xs-3'>
+               <user-sidebar />
        </div>
        <div class='col-xs-8'>
                <h4>Your grades</h4>
index 3dd5111..dbb5252 100644 (file)
@@ -73,7 +73,7 @@ redef class MDoc
                           not lines.first.has_prefix("\t") then
                                # parse synopsys
                                var syn = inline_proc.process(lines.shift)
-                               res.add "<p class=\"synopsys\">{syn}</p>"
+                               res.add "<h1 class=\"synopsys\">{syn}</h1>"
                        end
                end
                # check for annotations
index 42dc5dd..982e206 100644 (file)
@@ -232,12 +232,19 @@ redef class Catalog
                var name = mpackage.name.html_escape
                res.more_head.add """<title>{{{name}}}</title>"""
 
-               res.add """
-<div class="content">
-<h1 class="package-name">{{{name}}}</h1>
-"""
+               res.add """<div class="content">"""
+
                var mdoc = mpackage.mdoc_or_fallback
-               if mdoc != null then res.add mdoc.html_documentation
+               if mdoc == null then
+                       res.add """<h1 class="package-name">{{{name}}}</h1>"""
+               else
+                       res.add """
+<div style="float: left">
+       <h1 class="package-name">{{{name}}}&nbsp;-&nbsp;</h1>
+</div>
+"""
+                       res.add mdoc.html_documentation
+               end
 
                res.add "<h2>Content</h2>"
                var ot = new OrderedTree[MConcern]
index 95b1671..42e1df0 100644 (file)
 # Runs a webserver based on nitcorn that render things from model.
 module nitweb
 
-import popcorn::pop_auth
 import frontend
 import web
 import doc::doc_down
 
-redef class NitwebConfig
-
-       # Github client id used for Github OAuth login.
-       #
-       # * key: `github.client_id`
-       # * default: ``
-       fun github_client_id: String do return ini["github.client.id"] or else ""
-
-       # Github client secret used for Github OAuth login.
-       #
-       # * key: `github.client_secret`
-       # * default: ``
-       fun github_client_secret: String do return ini["github.client.secret"] or else ""
-end
-
 redef class ToolContext
 
        # Path to app config file.
index 854eb3a..1f37ffb 100644 (file)
@@ -19,7 +19,8 @@ import neo
 import model
 import frontend
 
-var test_name = "test_{get_time.to_s}"
+var test_id = "NIT_TESTING_ID".environ
+var test_name = "test_{test_id}"
 
 # init tool
 var toolcontext = new ToolContext
diff --git a/src/web/api_auth.nit b/src/web/api_auth.nit
new file mode 100644 (file)
index 0000000..80cce5d
--- /dev/null
@@ -0,0 +1,40 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module api_auth
+
+import web_base
+import popcorn::pop_auth
+
+redef class NitwebConfig
+
+       # Github client id used for Github OAuth login.
+       #
+       # * key: `github.client_id`
+       # * default: ``
+       fun github_client_id: String do return ini["github.client.id"] or else ""
+
+       # Github client secret used for Github OAuth login.
+       #
+       # * key: `github.client_secret`
+       # * default: ``
+       fun github_client_secret: String do return ini["github.client.secret"] or else ""
+end
+
+redef class APIRouter
+       redef init do
+               super
+               use("/user", new GithubUser)
+       end
+end
index 2e5294e..36d7e98 100644 (file)
@@ -15,6 +15,7 @@
 # Components required to build a web server about the nit model.
 module web
 
+import api_auth
 import api_model
 import api_catalog
 import api_graph
index f97fee4..dfc03c1 100644 (file)
    </div>
   </nav>
  </div>
-<div class="content">
-<h1 class="package-name">test_prog</h1>
-<div class="nitdoc"><p class="synopsys">Test program for model tools.</p><p>This program creates a fake model that can be used to test tools like:</p>
+<div class="content"><div style="float: left">
+       <h1 class="package-name">test_prog&nbsp;-&nbsp;</h1>
+</div>
+<div class="nitdoc"><h1 class="synopsys">Test program for model tools.</h1><p>This program creates a fake model that can be used to test tools like:</p>
 <ul>
 <li><code class="nitcode"><span class="nitcode"><span class="line"><span class="nc_i">nitdoc</span></span></span></code></li>
 <li><code class="nitcode"><span class="nitcode"><span class="line"><span class="nc_i">nitmetrics</span></span></span></code></li>
index 5575949..e556349 100644 (file)
@@ -14,7 +14,7 @@
 
 import neo4j
 
-var key = get_time
+var key = "NIT_TESTING_ID".environ.to_i
 
 var srv = new Neo4jServer
 srv.start_quiet
index 7455557..35f550c 100644 (file)
@@ -17,7 +17,7 @@ import neo4j
 var srv = new Neo4jServer
 srv.start_quiet
 
-var key = get_time
+var key = "NIT_TESTING_ID".environ.to_i
 
 var andres = new NeoNode
 andres.labels.add_all(["PERSON", "MALE"])
index ff3be6f..a228993 100644 (file)
@@ -18,19 +18,20 @@ module test_postgres_native
 
 import postgresql::native_postgres
 
+var db_suffix = "NIT_TESTING_ID".environ
 var db = new NativePostgres.connectdb("dbname=postgres")
 assert postgres_open: db.status.is_ok else print_error db.error
 
-var result = db.exec("CREATE TABLE IF NOT EXISTS animals (aname TEXT PRIMARY KEY, class TEXT NOT NULL, sex INTEGER)")
+var result = db.exec("CREATE TABLE IF NOT EXISTS animals_{db_suffix} (aname TEXT PRIMARY KEY, class TEXT NOT NULL, sex INTEGER)")
 assert postgres_create_table: result.status.is_ok else print_error db.error
 
-result = db.exec("INSERT INTO animals VALUES('Whale', 'mammal', 1)")
+result = db.exec("INSERT INTO animals_{db_suffix} VALUES('Whale', 'mammal', 1)")
 assert postgres_insert_1: result.status.is_ok else print_error db.error
 
-result = db.exec("INSERT INTO animals VALUES('Snake', 'reptile', 0)")
+result = db.exec("INSERT INTO animals_{db_suffix} VALUES('Snake', 'reptile', 0)")
 assert postgres_insert_2: result.status.is_ok else print_error db.error
 
-result = db.exec("SELECT * FROM animals")
+result = db.exec("SELECT * FROM animals_{db_suffix}")
 assert postgres_select: result.status.is_ok else print_error db.error
 
 assert postgres_ntuples: result.ntuples == 2 else print_error db.error
@@ -50,16 +51,16 @@ for i in [0..rows[ do
   print fields
 end
 
-result = db.exec("DELETE FROM animals WHERE aname = 'Lioness'")
+result = db.exec("DELETE FROM animals_{db_suffix} WHERE aname = 'Lioness'")
 assert postgres_delete_1: result.status.is_ok else print_error db.error
 
-result = db.exec("DELETE FROM animals WHERE aname = 'Snake'")
+result = db.exec("DELETE FROM animals_{db_suffix} WHERE aname = 'Snake'")
 assert postgres_delete_2: result.status.is_ok else print_error db.error
 
-result = db.prepare("PREPARED_INSERT", "INSERT INTO animals(aname, class, sex) VALUES ($1, $2, $3)", 3)
+result = db.prepare("PREPARED_INSERT", "INSERT INTO animals_{db_suffix}(aname, class, sex) VALUES ($1, $2, $3)", 3)
 assert postgres_prepare: result.status.is_ok else print_error db.error
 
-result = db.exec("DELETE FROM animals WHERE aname = 'Frog'")
+result = db.exec("DELETE FROM animals_{db_suffix} WHERE aname = 'Frog'")
 assert postgres_delete_3: result.status.is_ok else print_error db.error
 
 var values = ["Frog", "Anphibian", "1"]
@@ -68,6 +69,6 @@ var formats = [0,0,0]
 result = db.exec_prepared("PREPARED_INSERT", 3, values, lengths, formats,0)
 assert postgres_exec_prepared: result.status.is_ok else print_error db.error
 
-result = db.exec("DROP TABLE animals")
+result = db.exec("DROP TABLE animals_{db_suffix}")
 assert postgres_drop_table: result.status.is_ok else print_error db.error
 db.finish
index 9565335..900aac9 100644 (file)
@@ -18,22 +18,23 @@ module test_postgres_nity
 
 import postgresql::postgres
 
+var db_suffix = "NIT_TESTING_ID".environ
 var db = new Postgres.open("dbname=postgres")
 assert open_db: not db.is_closed else print db.error
 
-assert create_table: db.create_table("IF NOT EXISTS users (uname TEXT PRIMARY KEY, pass TEXT NOT NULL, activated INTEGER, perc FLOAT)") else
+assert create_table: db.create_table("IF NOT EXISTS users_{db_suffix} (uname TEXT PRIMARY KEY, pass TEXT NOT NULL, activated INTEGER, perc FLOAT)") else
   print db.error
 end
 
-assert insert1: db.insert("INTO users VALUES('Bob', 'zzz', 1, 77.7)") else
+assert insert1: db.insert("INTO users_{db_suffix} VALUES('Bob', 'zzz', 1, 77.7)") else
   print db.error
 end
 
-assert insert2: db.insert("INTO users VALUES('Guilherme', 'xxx', 1, 88)") else
+assert insert2: db.insert("INTO users_{db_suffix} VALUES('Guilherme', 'xxx', 1, 88)") else
   print db.error
 end
 
-var result = db.raw_execute("SELECT * FROM users")
+var result = db.raw_execute("SELECT * FROM users_{db_suffix}")
 
 assert raw_exec: result.is_ok else print db.error
 
@@ -42,7 +43,7 @@ assert postgres_fname: result.fname(0) == "uname" else print_error db.error
 assert postgres_isnull: result.is_null(0,0) == false else print_error db.error
 assert postgres_value: result.value(0,0) == "Bob" else print_error db.error
 
-assert drop_table: db.execute("DROP TABLE users") else print db.error
+assert drop_table: db.execute("DROP TABLE users_{db_suffix}") else print db.error
 
 db.finish