Commit ba7d3101 by Prajeesh K V

added gitdashboard project

1 parent bbe2e737
......@@ -5,7 +5,9 @@ GitHub Dashboard is Web Results Parser Web application which parse the GitHub se
GitHub Dashboard identifies the following :
Github url and description of top 50 projects having highest stars.
Unique list of programming languages involved in top 50 projects.
Average star rating of all top 50 projects.
## Building & Running application
......
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>github-dashboard</groupId>
<artifactId>github-dashboard</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.7.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>xsoup</artifactId>
<version>0.3.1</version>
</dependency>
</dependencies>
<build>
<finalName>github-dashboard</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/libs-release</url>
</repository>
<repository>
<id>org.jboss.repository.releases</id>
<name>JBoss Maven Release Repository</name>
<url>https://repository.jboss.org/nexus/content/repositories/releases</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
</project>
\ No newline at end of file
package com.github.dashboard.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String args[]) {
SpringApplication.run(App.class, args);
}
}
package com.github.dashboard.app.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource("application.properties")
public class Appconfig {
}
package com.github.dashboard.app.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class DashboardController {
@RequestMapping("/dashboard")
public String home() {
return "dashboard";
}
}
package com.github.dashboard.app.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.github.dashboard.app.model.Repository;
import com.github.dashboard.app.model.SearchRequest;
import com.github.dashboard.app.model.SearchResponse;
import com.github.dashboard.app.service.SearchService;
@RestController
public class SearchController {
@Autowired
SearchService searchService;
@RequestMapping(value = "/search", method = RequestMethod.GET)
public SearchResponse search(@RequestParam String query) {
SearchResponse searchResponse = new SearchResponse();
SearchRequest searchRequest = new SearchRequest();
searchRequest.setQuery(query);
searchRequest.setSort("stars");
List<Repository> repositories = searchService.search(searchRequest);
searchResponse.setRepositories(repositories);
searchResponse.setLanguages(searchService.getUniqueLanguages(repositories));
searchResponse.setAvgStars(searchService.getAverageStars(repositories));
return searchResponse;
}
}
package com.github.dashboard.app.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Repository {
private String url;
private String description;
private String language;
private float star;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public float getStar() {
return star;
}
public void setStar(float star) {
this.star = star;
}
@Override
public String toString() {
return "Repository [url=" + url + ", description=" + description + ", language=" + language + ", star=" + star
+ "]";
}
}
package com.github.dashboard.app.model;
public class SearchRequest {
private String query;
private String sort;
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
public String getSort() {
return sort;
}
public void setSort(String sort) {
this.sort = sort;
}
}
package com.github.dashboard.app.model;
import java.util.List;
import java.util.Set;
public class SearchResponse {
private List<Repository> repositories;
private Set<String> languages;
private double avgStars;
public List<Repository> getRepositories() {
return repositories;
}
public void setRepositories(List<Repository> repositories) {
this.repositories = repositories;
}
public Set<String> getLanguages() {
return languages;
}
public void setLanguages(Set<String> languages) {
this.languages = languages;
}
public double getAvgStars() {
return avgStars;
}
public void setAvgStars(double avgStars) {
this.avgStars = avgStars;
}
@Override
public String toString() {
return "SearchResponse [repositories=" + repositories + ", languages=" + languages + ", avgStars=" + avgStars
+ "]";
}
}
package com.github.dashboard.app.service;
import java.util.List;
import java.util.Set;
import com.github.dashboard.app.model.Repository;
import com.github.dashboard.app.model.SearchRequest;
public interface SearchService {
public List<Repository> search(SearchRequest searchRequest);
public Set<String> getUniqueLanguages(List<Repository> repositories);
public double getAverageStars(List<Repository> repositories);
}
package com.github.dashboard.app.serviceimpl;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponentsBuilder;
import com.github.dashboard.app.model.Repository;
import com.github.dashboard.app.model.SearchRequest;
import com.github.dashboard.app.service.SearchService;
import com.github.dashboard.app.util.HTMLUtil;
@Service
public class SearchServiceImpl implements SearchService {
@Value("${url}")
private String url;
@Override
public List<Repository> search(SearchRequest searchRequest) {
String pageUrl;
List<Repository> repositories = new ArrayList<>();
for (int index = 1; index <= 5; index++) {
pageUrl = getPageUrl(searchRequest, index);
repositories.addAll(HTMLUtil.extractRepositories(pageUrl));
}
return repositories;
}
private String getPageUrl(SearchRequest searchRequest, int pageNo) {
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url)
// Add query parameter
.queryParam("q", searchRequest.getQuery() != null ? searchRequest.getQuery() : "")
.queryParam("s", searchRequest.getSort()).queryParam("p", pageNo);
return builder.build().toUri().toString();
}
@Override
public Set<String> getUniqueLanguages(List<Repository> repositories) {
Set<String> languages = new HashSet<>();
repositories.forEach(repository -> {
if (StringUtils.hasText(repository.getLanguage())) {
languages.add(repository.getLanguage());
}
});
return languages;
}
@Override
public double getAverageStars(List<Repository> repositories) {
return repositories.stream()
.mapToDouble(Repository::getStar)
.average().getAsDouble();
}
}
package com.github.dashboard.app.util;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import com.github.dashboard.app.model.Repository;
public class HTMLUtil {
public static List<Repository> extractRepositories(String path) {
List<Repository> repositories = new ArrayList<>();
try {
Document document = Jsoup.connect(path).get();
Elements reportList = document.select(".repo-list-item");
reportList.forEach(reportListItem -> {
Repository repository = new Repository();
addRepositoryUrl(reportListItem, repository);
addRepositoryDescription(reportListItem, repository);
addRepositoryLanguage(reportListItem, repository);
addRepositoryStar(reportListItem, repository);
repositories.add(repository);
});
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return repositories;
}
private static void addRepositoryUrl(Element reportListItem, Repository repository) {
Elements url = reportListItem.select("div > h3 > a");
if (!CollectionUtils.isEmpty(url)) {
repository.setUrl("https://github.com" + url.get(0).attr("href"));
}
if(!StringUtils.hasText(repository.getUrl())) {
repository.setDescription("No url present");
}
}
private static void addRepositoryDescription(Element reportListItem, Repository repository) {
Elements description = reportListItem.select("div > p.col-9");
if (!CollectionUtils.isEmpty(description)) {
repository.setDescription(description.get(0).text());
}
if(!StringUtils.hasText(repository.getDescription())) {
repository.setDescription("No description provided");
}
}
private static void addRepositoryLanguage(Element reportListItem, Repository repository) {
Elements language = reportListItem.select("div.d-table-cell");
if (!CollectionUtils.isEmpty(language)) {
repository.setLanguage(language.get(0).text());
}
}
private static void addRepositoryStar(Element reportListItem, Repository repository) {
Elements star = reportListItem.select("div > a.muted-link");
if (!CollectionUtils.isEmpty(star)) {
repository.setStar(getStarValueFromText(star.get(0).text()));
}
}
private static float getStarValueFromText(String text) {
float value = 0f;
int multFactor = 1;
if (StringUtils.hasText(text)) {
if (text.trim().toUpperCase().endsWith("K")) {
multFactor = 1000;
} else if (text.trim().toUpperCase().endsWith("M")) {
multFactor = 1000 * 1000;
}
value = Float.parseFloat(text.trim().replaceAll("[^0-9]+", "")) * multFactor;
}
return value;
}
}
url=https://github.com/search
#https://github.com/search?q=artifical+intelligence&type=Repositories&p=1
function load(query) {
$("#loading").show();
$.get("/search?query=" + query , function(data){
$('#repo-table').DataTable({
data: data.repositories,
order: [[ 2, "desc" ]],
destroy: true,
columns: [
{ title: "Url", data : "url" , "render": function ( data, type, row ) {
return "<a href='"+ data + "'>" + data + "</a>";
}},
{ title: "Description" , data : "description" },
{ title: "stars" , data : "star" , "visible": false }
]
});
$('#lang').html("");
$.each(data.languages, function (index, item) {
$('#lang').append(item);
if(index < data.languages.length - 1) {
$('#lang').append(",");
} else {
$('#lang').append(".");
}
});
$('#avg-star').html(data.avgStars);
$("#loading").hide();
});
}
$(document).ready(function(){
$("#search-box").val("artifical intelligence")
load("artifical intelligence");
$("#search-button").click(function(){
$("#loading").show();
query = $("#search-box").val();
if(query.replace(/\s/g, "") !== ''){
load(query);
}
});
$('#search-box').keydown(function(event){
var keyCode = (event.keyCode ? event.keyCode : event.which);
if (keyCode == 13) {
$('#search-button').trigger('click');
}
});
});
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>GitHub DashBoard</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta/css/bootstrap.css">
</link>
<link rel="stylesheet"
href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css">
</link>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script
src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js"
integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1"
crossorigin="anonymous"></script>
<script
src="https://cdn.datatables.net/1.10.16/js/dataTables.bootstrap4.min.js"></script>
<script src="/app.js"></script>
</head>
<body>
<div class="container">
<ol class="breadcrumb" style="background: #888">
<li class="breadcrumb-item active" style="color: white">GitHub Dashboard</li>
</ol>
<div class="content">
<div class="row">
<div class="col-lg-6">
<div class="input-group">
<input type="text" class="form-control"
placeholder="Search for..." id="search-box"> </input><span
class="input-group-btn">
<button class="btn btn-secondary" type="button" id="search-button">Search</button>
</span>
</div>
<span id="loading" style="color: green;">Loading...</span>
</div>
</div>
<div style="padding-top: 3%;"></div>
<div class="alert alert-success" role="alert">
<div>Languages in Top 50 : <span id="lang"></span></div> <div>Average Star Rating : <span id="avg-star"></span></div>
</div>
<div id="repo-table-div" style="padding-top: 3%;">
<table id="repo-table" class="cell-border">
</table>
</div>
<span style="width: 50%;"> </span>
</div>
</div>
</body>
</html>
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!