This is the codeAbility Sharing Platform! Learn more about the codeAbility Sharing Platform.

Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • development/sharing/codeability-sharing-platform
1 result
Show changes
Commits on Source (4)
Showing
with 1022 additions and 35 deletions
......@@ -6,7 +6,7 @@
},
"rules": {
"@typescript-eslint/tslint/config": [
"error",
"warn",
{
"lintFile": "./tslint.json"
}
......
{
"fluentMethods": true,
"clientRootFolder": "",
"relationships": [],
"fields": [
{
"fieldName": "views",
"fieldType": "Integer"
},
{
"fieldName": "downloads",
"fieldType": "Integer",
"fieldValidateRules": ["required"]
},
{
"fieldName": "exerciseID",
"fieldType": "Integer"
}
],
"changelogDate": "20210319162139",
"dto": "mapstruct",
"searchEngine": "elasticsearch",
"service": "serviceImpl",
"entityTableName": "statistics",
"databaseType": "sql",
"readOnly": false,
"jpaMetamodelFiltering": false,
"pagination": "infinite-scroll"
}
......@@ -30,19 +30,15 @@
"clientTheme": "none",
"clientThemeVariant": "",
"creationTimestamp": 1593593458485,
"testFrameworks": [
"protractor"
],
"testFrameworks": ["protractor"],
"jhiPrefix": "jhi",
"entitySuffix": "",
"dtoSuffix": "DTO",
"otherModules": [],
"enableTranslation": true,
"nativeLanguage": "en",
"languages": [
"en",
"de"
],
"blueprints": []
"languages": ["en", "de"],
"blueprints": [],
"lastLiquibaseTimestamp": 1616170899000
}
}
......@@ -48,6 +48,7 @@ public class CacheConfiguration {
createCache(cm, at.ac.uibk.gitsearch.domain.User.class.getName());
createCache(cm, at.ac.uibk.gitsearch.domain.Authority.class.getName());
createCache(cm, at.ac.uibk.gitsearch.domain.User.class.getName() + ".authorities");
createCache(cm, at.ac.uibk.gitsearch.domain.Statistics.class.getName());
// jhipster-needle-ehcache-add-entry
};
}
......
......@@ -154,6 +154,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/statistics/**").permitAll()
.antMatchers("/oauth2/**").permitAll()
.antMatchers("/api/search/**").permitAll() // search is always allowed, may return more data, if authenticated
.antMatchers("/api/pluginIF/**").permitAll() // plugins calls are always allowed, security by tokens
......
package at.ac.uibk.gitsearch.domain;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.*;
import javax.validation.constraints.*;
import org.springframework.data.elasticsearch.annotations.FieldType;
import java.io.Serializable;
/**
* A Statistics.
*/
@Entity
@Table(name = "statistics")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@org.springframework.data.elasticsearch.annotations.Document(indexName = "statistics")
public class Statistics implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "views")
private Integer views;
@NotNull
@Column(name = "downloads", nullable = false)
private Integer downloads;
@Column(name = "exercise_id")
private Long exerciseID;
// jhipster-needle-entity-add-field - JHipster will add fields here
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getViews() {
return views;
}
public Statistics views(Integer views) {
this.views = views;
return this;
}
public void setViews(Integer views) {
this.views = views;
}
public Integer getDownloads() {
return downloads;
}
public Statistics downloads(Integer downloads) {
this.downloads = downloads;
return this;
}
public void setDownloads(Integer downloads) {
this.downloads = downloads;
}
public Long getExerciseID() {
return exerciseID;
}
public Statistics exerciseID(Long exerciseID) {
this.exerciseID = exerciseID;
return this;
}
public void setExerciseID(Long exerciseID) {
this.exerciseID = exerciseID;
}
// jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Statistics)) {
return false;
}
return id != null && id.equals(((Statistics) o).id);
}
@Override
public int hashCode() {
return 31;
}
// prettier-ignore
@Override
public String toString() {
return "Statistics{" +
"id=" + getId() +
", views=" + getViews() +
", downloads=" + getDownloads() +
", exerciseID=" + getExerciseID() +
"}";
}
}
package at.ac.uibk.gitsearch.repository;
import at.ac.uibk.gitsearch.domain.Statistics;
import at.ac.uibk.gitsearch.service.dto.StatisticsDTO;
import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.repository.*;
import org.springframework.stereotype.Repository;
/**
* Spring Data repository for the Statistics entity.
*/
@Repository
public interface StatisticsRepository extends JpaRepository<Statistics, Long> {
Optional<Statistics> findByExerciseID(Long id);
}
......@@ -46,11 +46,13 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import at.ac.uibk.gitsearch.config.ApplicationProperties;
import at.ac.uibk.gitsearch.service.StatisticsService;
import at.ac.uibk.gitsearch.service.dto.AutoCompleteEntry;
import at.ac.uibk.gitsearch.service.dto.SearchInputDTO;
import at.ac.uibk.gitsearch.service.dto.SearchResultDTO;
import at.ac.uibk.gitsearch.service.dto.SearchResultsDTO;
import at.ac.uibk.gitsearch.service.dto.UserProvidedMetadataDTO.Person;
import at.ac.uibk.gitsearch.service.impl.StatisticsServiceImpl;
@Repository
public class MetaDataRepository {
......@@ -63,9 +65,13 @@ public class MetaDataRepository {
private static final int FRAGMENT_SIZE = 5000;
public MetaDataRepository(RestHighLevelClient elasticsearchClient, ApplicationProperties properties) {
private final StatisticsService statisticsService;
public MetaDataRepository(RestHighLevelClient elasticsearchClient, ApplicationProperties properties, StatisticsService statisticsService) {
this.elasticsearchClient = elasticsearchClient;
this.properties = properties;
this.statisticsService = statisticsService;
}
......@@ -385,7 +391,7 @@ public class MetaDataRepository {
float maxScore = searchResponse.getHits().getMaxScore();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
final List<SearchResultDTO> searchResults = new ArrayList<>();
for (SearchHit searchHit : searchResponse.getHits().getHits()) {
......@@ -394,6 +400,8 @@ public class MetaDataRepository {
int ranking5 = 1;
if (maxScore>0.0f) ranking5 = (int) ((hitScore*5.0)/maxScore+0.5f);
parsedSearchHit.setRanking5(ranking5);
parsedSearchHit.setDownloads(0);
parsedSearchHit.setViews(0);
searchResults.add(parsedSearchHit);
}
......
package at.ac.uibk.gitsearch.repository.search;
import at.ac.uibk.gitsearch.domain.Statistics;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
/**
* Spring Data Elasticsearch repository for the {@link Statistics} entity.
*/
public interface StatisticsSearchRepository extends ElasticsearchRepository<Statistics, Long> {
}
package at.ac.uibk.gitsearch.service;
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.codeability.sharing.plugins.api.ShoppingBasket;
import org.codeability.sharing.plugins.api.ShoppingBasket.ExerciseInfo;
import org.codeability.sharing.plugins.api.ShoppingBasket.UserInfo;
import org.gitlab4j.api.GitLabApi;
import org.gitlab4j.api.GitLabApiException;
import org.gitlab4j.api.ProjectApi;
import org.gitlab4j.api.RepositoryApi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import at.ac.uibk.gitsearch.repository.gitlab.GitLabRepository;
import at.ac.uibk.gitsearch.security.jwt.TokenProvider.GitLabAccessInfo;
import at.ac.uibk.gitsearch.service.dto.SearchResultDTO;
/**
* Service for exercise/course search results
* <p>
*/
@Service
public class GitlabService {
@Autowired
private PluginManagementService pluginManagementService;
@Autowired
private GitLabRepository gitLabRepository;
private final Logger log = LoggerFactory.getLogger(ShoppingBasketService.class);
public Boolean repositoryExists(String projectID) {
final GitLabApi gitLabApi = gitLabRepository.getGitLabApi(Optional.empty());
final ProjectApi gitLabProjectApi = gitLabApi.getProjectApi();
try{
return gitLabProjectApi.getProject(projectID) != null;}
catch(GitLabApiException e){
log.error(e.getMessage(), e);
return false;
}
}
public InputStream getRepositoryZip(String exerciseID) throws GitLabApiException, IOException {
final GitLabApi gitLabApi = gitLabRepository.getGitLabApi(Optional.empty());
return rePackageGitLabProjectZip(new ZipInputStream(gitLabApi.getRepositoryApi().getRepositoryArchive(exerciseID, "HEAD", "zip")), "from project " + exerciseID);
}
/**
* chops of the main folder, and brings every file one level up. Also deleting
* all plain files in main folder.
*
* @param zipIn the zip to be repackaged
* @param originalLocation the original location. For debug purposes only.
* @return
* @throws IOException
*/
protected InputStream rePackageGitLabProjectZip(ZipInputStream zipIn, String originalLocation) throws IOException {
final PipedInputStream pis = new PipedInputStream(1024*256);
final PipedOutputStream pos = new PipedOutputStream(pis);
Runnable rePackage = () -> {
try (ZipOutputStream zipOut = new ZipOutputStream(pos)) {
ZipEntry zipInEntry = zipIn.getNextEntry();
String prefix = "";
if (zipInEntry.isDirectory()) { // main directory is prefix to all entries
prefix = zipInEntry.getName();
}
while (zipInEntry != null) {
if (zipInEntry.getName().startsWith(prefix)) {
String newName = zipInEntry.getName().substring(prefix.length());
if (!StringUtils.isEmpty(newName)) {
ZipEntry zipOutEntry = new ZipEntry(newName);
if (zipInEntry.isDirectory()) {
log.debug("ignoring directory {}", zipInEntry.getName());
zipOut.putNextEntry(zipOutEntry);
} else {
zipOut.putNextEntry(zipOutEntry);
StreamUtils.copy(zipIn, zipOut);
zipOut.closeEntry();
}
}}
zipInEntry = zipIn.getNextEntry();
}
zipIn.close();
} catch (IOException e) {
log.error("Cannot rezip file from {}", originalLocation);
}
};
new Thread(rePackage).start();
return pis;
}
}
package at.ac.uibk.gitsearch.service;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.zip.ZipInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -17,6 +21,8 @@ import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.gitlab4j.api.GitLabApi;
import org.gitlab4j.api.GitLabApiException;
import at.ac.uibk.gitsearch.repository.gitlab.GitLabRepository;
import at.ac.uibk.gitsearch.repository.search.MetaDataRepository;
......@@ -43,6 +49,8 @@ public class SearchService {
protected GitLabRepository gitLabRepository;
@Autowired
protected PluginManagementService pluginManagementService;
@Autowired
protected ShoppingBasketService shoppingBasketService;
/** just for test implementation **/
public static final int NUM_TESTRESULTS = 23;
......@@ -102,10 +110,11 @@ public class SearchService {
* @return
* @throws IOException
*/
public List<AutoCompleteEntry> getProgrammingLanguageAutoComplete(String programmingLanguagePrefix) throws IOException {
public List<AutoCompleteEntry> getProgrammingLanguageAutoComplete(String programmingLanguagePrefix)
throws IOException {
return metaDataRepository.getProgrammingLanguageAutoComplete(programmingLanguagePrefix);
}
/**
* returns the result page
*
......@@ -115,19 +124,21 @@ public class SearchService {
*/
public SearchResultsDTO searchResultPage(SearchInputDTO searchInput, long first, int length) throws IOException {
log.debug("Searchrequest for {} ", searchInput);
final SearchResultsDTO pageDetails = metaDataRepository.pageDetails(searchInput, length, tokenProvider.getCurrentPrincipal());
pageDetails.getSearchResult().stream().forEach(
hit -> pluginManagementService.getRegisteredPluginConfigs().stream()
.forEach(config -> config.getActions().values().stream().filter(action -> action.isApplicable(hit)).forEach(action -> hit.getSupportedActions().add(action.getPluginActionInfo()))) );
final SearchResultsDTO pageDetails = metaDataRepository.pageDetails(searchInput, length,
tokenProvider.getCurrentPrincipal());
pageDetails.getSearchResult().stream()
.forEach(hit -> pluginManagementService.getRegisteredPluginConfigs().stream()
.forEach(config -> config.getActions().values().stream()
.filter(action -> action.isApplicable(hit))
.forEach(action -> hit.getSupportedActions().add(action.getPluginActionInfo()))));
pageDetails.getSearchResult().stream().forEach(this::fixImageURL);
return pageDetails;
// return readTestResults(searchInput.getFulltextQuery(), first, length);
// return readTestResults(searchInput.getFulltextQuery(), first, length);
}
private void fixImageURL(SearchResultDTO metaData) {
String image = metaData.getMetadata().getImage();
......@@ -135,7 +146,8 @@ public class SearchService {
try {
if (image != null) {
URI url = new URI(image);
if(url.isAbsolute()) return;
if (url.isAbsolute())
return;
String httpUrlToRepo = metaData.getProject().getUrl();
String baseRepoURL = httpUrlToRepo + "/-/raw/master/";
final URI resolvedImageUrl = new URI(baseRepoURL).resolve(url);
......@@ -164,7 +176,7 @@ public class SearchService {
return;
}
metaData.getMetadata().setImage(baseUrl + "/content/img/gitLab.png");
return;
return;
} catch (URISyntaxException e) {
log.warn("Cannot parse image url {} for {}", metaData.getMetadata().getImage(),
......@@ -204,22 +216,49 @@ public class SearchService {
long recordNr = first;
// This loop is only used for testing to get more results.
for (int i = 0; i < 12; ++i) {
metadataPos = 0; // also for testing, remove later
while (metadataPos < length && metadataPos < loadedMetaData.size()) {
final SearchResultDTO loadedMetaDataRecord = new SearchResultDTO(loadedMetaData.get(metadataPos++));
if (loadedMetaDataRecord.toString().contains(searchString)) {
loadedMetaDataRecord.getMetadata().setTitle("#" + (recordNr + 1) + " " + loadedMetaDataRecord.getMetadata().getTitle());
result.add(loadedMetaDataRecord);
recordNr++;
log.debug("Added MetaData Record {}", loadedMetaData);
}
log.debug("{} does not contain {}", loadedMetaData, searchString);
}
}
metadataPos = 0; // also for testing, remove later
while (metadataPos < length && metadataPos < loadedMetaData.size()) {
final SearchResultDTO loadedMetaDataRecord = new SearchResultDTO(loadedMetaData.get(metadataPos++));
if (loadedMetaDataRecord.toString().contains(searchString)) {
loadedMetaDataRecord.getMetadata()
.setTitle("#" + (recordNr + 1) + " " + loadedMetaDataRecord.getMetadata().getTitle());
result.add(loadedMetaDataRecord);
recordNr++;
log.debug("Added MetaData Record {}", loadedMetaData);
}
log.debug("{} does not contain {}", loadedMetaData, searchString);
}
}
}
return new SearchResultsDTO(result, NUM_TESTRESULTS, first);
}
public File exportExercise(long exerciseId) throws IOException {
try{
final GitLabApi gitLabApi = gitLabRepository.getGitLabApi(tokenProvider.getGitLabAccessInfo());
InputStream inputFile = shoppingBasketService.rePackageGitLabProjectZip(new ZipInputStream(gitLabApi.getRepositoryApi().getRepositoryArchive((int)(long)exerciseId, "HEAD", "zip")), "from project " + String.valueOf(exerciseId));
File file = new File("exercise" + String.valueOf(exerciseId) + ".zip");
return copyInputStreamToFile(inputFile, file);}
catch(GitLabApiException exception){
log.error(exception.getMessage());
}
return null;
}
private File copyInputStreamToFile(InputStream inputStream, File file) throws IOException {
// append = false
try (FileOutputStream outputStream = new FileOutputStream(file, false)) {
int read;
byte[] bytes = new byte[8192];
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
return file;
}
}
}
package at.ac.uibk.gitsearch.service;
import at.ac.uibk.gitsearch.service.dto.StatisticsDTO;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.Optional;
/**
* Service Interface for managing {@link at.ac.uibk.gitsearch.domain.Statistics}.
*/
public interface StatisticsService {
/**
* Save a statistics.
*
* @param statisticsDTO the entity to save.
* @return the persisted entity.
*/
StatisticsDTO save(StatisticsDTO statisticsDTO);
/**
* Get all the statistics.
*
* @param pageable the pagination information.
* @return the list of entities.
*/
Page<StatisticsDTO> findAll(Pageable pageable);
/**
* Get the "id" statistics.
*
* @param id the id of the entity.
* @return the entity.
*/
Optional<StatisticsDTO> findOne(Long id);
/**
* Delete the "id" statistics.
*
* @param id the id of the entity.
*/
void delete(Long id);
/**
* Search for the statistics corresponding to the query.
*
* @param query the query of the search.
*
* @param pageable the pagination information.
* @return the list of entities.
*/
Page<StatisticsDTO> search(String query, Pageable pageable);
Optional<StatisticsDTO> findOneByExerciseID(Long id);
}
......@@ -69,10 +69,29 @@ public class SearchResultDTO {
private int ranking5;
private List<PluginActionInfo> supportedActions = new ArrayList<>(2);
private Integer views;
private Integer downloads;
public SearchResultDTO() {
// default constructor
}
public Integer getDownloads() {
return downloads;
}
public void setDownloads(Integer downloads) {
this.downloads = downloads;
}
public Integer getViews() {
return views;
}
public void setViews(Integer views) {
this.views = views;
}
/**
* clone constructor
*
......
package at.ac.uibk.gitsearch.service.dto;
import javax.validation.constraints.*;
import java.io.Serializable;
/**
* A DTO for the {@link at.ac.uibk.gitsearch.domain.Statistics} entity.
*/
public class StatisticsDTO implements Serializable {
private Long id;
private Integer views;
private Integer downloads;
private Long exerciseID;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getViews() {
return views;
}
public void setViews(Integer views) {
this.views = views;
}
public Integer getDownloads() {
return downloads;
}
public void setDownloads(Integer downloads) {
this.downloads = downloads;
}
public Long getExerciseID() {
return exerciseID;
}
public void setExerciseID(Long exerciseID) {
this.exerciseID = exerciseID;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof StatisticsDTO)) {
return false;
}
return id != null && id.equals(((StatisticsDTO) o).id);
}
@Override
public int hashCode() {
return 31;
}
// prettier-ignore
@Override
public String toString() {
return "StatisticsDTO{" +
"id=" + getId() +
", views=" + getViews() +
", downloads=" + getDownloads() +
", exerciseID=" + getExerciseID() +
"}";
}
}
package at.ac.uibk.gitsearch.service.impl;
import at.ac.uibk.gitsearch.service.StatisticsService;
import at.ac.uibk.gitsearch.domain.Statistics;
import at.ac.uibk.gitsearch.repository.StatisticsRepository;
import at.ac.uibk.gitsearch.repository.search.StatisticsSearchRepository;
import at.ac.uibk.gitsearch.service.dto.StatisticsDTO;
import at.ac.uibk.gitsearch.service.mapper.StatisticsMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import static org.elasticsearch.index.query.QueryBuilders.*;
/**
* Service Implementation for managing {@link Statistics}.
*/
@Service
@Transactional
public class StatisticsServiceImpl implements StatisticsService {
private final Logger log = LoggerFactory.getLogger(StatisticsServiceImpl.class);
private final StatisticsRepository statisticsRepository;
private final StatisticsMapper statisticsMapper;
private final StatisticsSearchRepository statisticsSearchRepository;
public StatisticsServiceImpl(StatisticsRepository statisticsRepository, StatisticsMapper statisticsMapper, StatisticsSearchRepository statisticsSearchRepository) {
this.statisticsRepository = statisticsRepository;
this.statisticsMapper = statisticsMapper;
this.statisticsSearchRepository = statisticsSearchRepository;
}
@Override
public StatisticsDTO save(StatisticsDTO statisticsDTO) {
log.debug("Request to save Statistics : {}", statisticsDTO);
Statistics statistics = statisticsMapper.toEntity(statisticsDTO);
statistics = statisticsRepository.save(statistics);
StatisticsDTO result = statisticsMapper.toDto(statistics);
statisticsSearchRepository.save(statistics);
return result;
}
@Override
@Transactional(readOnly = true)
public Page<StatisticsDTO> findAll(Pageable pageable) {
log.debug("Request to get all Statistics");
return statisticsRepository.findAll(pageable)
.map(statisticsMapper::toDto);
}
@Override
@Transactional(readOnly = true)
public Optional<StatisticsDTO> findOne(Long id) {
log.debug("Request to get Statistics : {}", id);
return statisticsRepository.findById(id)
.map(statisticsMapper::toDto);
}
@Override
public Optional<StatisticsDTO> findOneByExerciseID(Long id) {
log.debug("Request to get Statistics by ExerciseId : {}", id);
return statisticsRepository.findByExerciseID(id)
.map(statisticsMapper::toDto);
}
@Override
public void delete(Long id) {
log.debug("Request to delete Statistics : {}", id);
statisticsRepository.deleteById(id);
statisticsSearchRepository.deleteById(id);
}
@Override
@Transactional(readOnly = true)
public Page<StatisticsDTO> search(String query, Pageable pageable) {
log.debug("Request to search for a page of Statistics for query {}", query);
return statisticsSearchRepository.search(queryStringQuery(query), pageable)
.map(statisticsMapper::toDto);
}
}
package at.ac.uibk.gitsearch.service.mapper;
import java.util.List;
/**
* Contract for a generic dto to entity mapper.
*
* @param <D> - DTO type parameter.
* @param <E> - Entity type parameter.
*/
public interface EntityMapper <D, E> {
E toEntity(D dto);
D toDto(E entity);
List <E> toEntity(List<D> dtoList);
List <D> toDto(List<E> entityList);
}
package at.ac.uibk.gitsearch.service.mapper;
import at.ac.uibk.gitsearch.domain.*;
import at.ac.uibk.gitsearch.service.dto.StatisticsDTO;
import org.mapstruct.*;
/**
* Mapper for the entity {@link Statistics} and its DTO {@link StatisticsDTO}.
*/
@Mapper(componentModel = "spring", uses = {})
public interface StatisticsMapper extends EntityMapper<StatisticsDTO, Statistics> {
default Statistics fromId(Long id) {
if (id == null) {
return null;
}
Statistics statistics = new Statistics();
statistics.setId(id);
return statistics;
}
}
package at.ac.uibk.gitsearch.web.rest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
import org.gitlab4j.api.GitLabApiException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import at.ac.uibk.gitsearch.es.model.DocumentInfo;
import at.ac.uibk.gitsearch.service.SearchService;
import at.ac.uibk.gitsearch.service.StatisticsService;
import at.ac.uibk.gitsearch.service.dto.AutoCompleteEntry;
import at.ac.uibk.gitsearch.service.dto.SearchInputDTO;
import at.ac.uibk.gitsearch.service.dto.SearchResultsDTO;
import at.ac.uibk.gitsearch.service.dto.StatisticsDTO;
import at.ac.uibk.gitsearch.web.util.HeaderUtil;
/**
* REST controller for managing {@link DocumentInfo}.
......@@ -27,12 +41,21 @@ import at.ac.uibk.gitsearch.service.dto.SearchResultsDTO;
@Transactional
public class SearchResource {
@Value("${jhipster.clientApp.name}")
private String applicationName;
private static final String ENTITY_NAME = "SearchResource";
private final Logger log = LoggerFactory.getLogger(SearchResource.class);
private final SearchService searchService;
public SearchResource(SearchService searchService) {
private final StatisticsService statisticsService;
public SearchResource(SearchService searchService, StatisticsService statisticsService) {
this.searchService = searchService;
this.statisticsService = statisticsService;
}
/**
......@@ -110,4 +133,63 @@ public class SearchResource {
}
/**
* POST /programming-exercises/:exerciseId/export-programmingExercise : sends all repositories and details of the programming exercise as zip
*
* @param exerciseId the id of the exercise to get the repos from
* ResponseEntity with status
* @throws IOException if something during the zip process went wrong
*/
@PostMapping("/programming-exercises/{exerciseId}/export-programming-exercise")
public ResponseEntity<Resource> exportProgrammingExercise(@PathVariable long exerciseId) throws IOException {
File zipFile = searchService.exportExercise(exerciseId);
if (zipFile == null) {
return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(applicationName, true, ENTITY_NAME, "internalServerError",
"There was an error on the server and the zip file could not be created.")).body(null);
}
/*
* Customized FileInputStream to delete and therefore clean up the returned files
*/
class NewFileInputStream extends FileInputStream {
File file;
public NewFileInputStream(File file) throws FileNotFoundException {
super(file);
this.file = file;
}
public void close() throws IOException {
super.close();
file.delete();
}
}
InputStreamResource resource = new InputStreamResource(new NewFileInputStream(zipFile));
log.debug("REST request to get Statistics for ExerciseID : {}", exerciseId);
Optional<StatisticsDTO> statisticsDTO = statisticsService.findOneByExerciseID(exerciseId);
if(statisticsDTO.isPresent()){
StatisticsDTO newStats = statisticsDTO.get();
newStats.setDownloads(newStats.getDownloads() + 1);
statisticsService.save(newStats);
log.debug("REST increased number of downloads for ExerciseID : {}", exerciseId);
}
if(!statisticsDTO.isPresent()){
StatisticsDTO newStats = new StatisticsDTO();
newStats.setDownloads(1);
newStats.setViews(1);
newStats.setExerciseID(exerciseId);
statisticsService.save(newStats);
log.debug("Created new statistics entry for exerciseID: {}", exerciseId);
}
return ResponseEntity.ok().contentLength(zipFile.length()).contentType(MediaType.APPLICATION_OCTET_STREAM).header("filename", zipFile.getName()).body(resource);
}
}
package at.ac.uibk.gitsearch.web.rest;
import at.ac.uibk.gitsearch.service.GitlabService;
import at.ac.uibk.gitsearch.service.StatisticsService;
import at.ac.uibk.gitsearch.web.rest.errors.BadRequestAlertException;
import at.ac.uibk.gitsearch.service.dto.StatisticsDTO;
import io.github.jhipster.web.util.HeaderUtil;
import io.github.jhipster.web.util.PaginationUtil;
import io.github.jhipster.web.util.ResponseUtil;
import org.gitlab4j.api.GitLabApiException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;
import javax.validation.Valid;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Optional;
import java.util.stream.StreamSupport;
import static org.elasticsearch.index.query.QueryBuilders.*;
/**
* REST controller for managing {@link at.ac.uibk.gitsearch.domain.Statistics}.
*/
@RestController
@RequestMapping("/api")
public class StatisticsResource {
private final Logger log = LoggerFactory.getLogger(StatisticsResource.class);
private static final String ENTITY_NAME = "statistics";
@Value("${jhipster.clientApp.name}")
private String applicationName;
private final StatisticsService statisticsService;
@Autowired
private final GitlabService gitlabService;
public StatisticsResource(StatisticsService statisticsService, GitlabService gitlabService) {
this.statisticsService = statisticsService;
this.gitlabService = gitlabService;
}
/**
* {@code POST /statistics} : Create a new statistics.
*
* @param statisticsDTO the statisticsDTO to create.
* @return the {@link ResponseEntity} with status {@code 201 (Created)} and with
* body the new statisticsDTO, or with status {@code 400 (Bad Request)}
* if the statistics has already an ID.
* @throws URISyntaxException if the Location URI syntax is incorrect.
*/
@PostMapping("/statistics")
@PreAuthorize("hasAnyRole('ADMIN')")
public ResponseEntity<StatisticsDTO> createStatistics(@Valid @RequestBody StatisticsDTO statisticsDTO)
throws URISyntaxException {
log.debug("REST request to save Statistics : {}", statisticsDTO);
if (statisticsDTO.getId() != null) {
throw new BadRequestAlertException("A new statistics cannot already have an ID", ENTITY_NAME, "idexists");
}
StatisticsDTO result = statisticsService.save(statisticsDTO);
return ResponseEntity
.created(new URI("/api/statistics/" + result.getId())).headers(HeaderUtil
.createEntityCreationAlert(applicationName, true, ENTITY_NAME, result.getId().toString()))
.body(result);
}
/**
* {@code PUT /statistics} : Updates an existing statistics.
*
* @param statisticsDTO the statisticsDTO to update.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body
* the updated statisticsDTO, or with status {@code 400 (Bad Request)}
* if the statisticsDTO is not valid, or with status
* {@code 500 (Internal Server Error)} if the statisticsDTO couldn't be
* updated.
* @throws URISyntaxException if the Location URI syntax is incorrect.
*/
@PutMapping("/statistics")
@PreAuthorize("hasAnyRole('ADMIN')")
public ResponseEntity<StatisticsDTO> updateStatistics(@Valid @RequestBody StatisticsDTO statisticsDTO)
throws URISyntaxException {
log.debug("REST request to update Statistics : {}", statisticsDTO);
if (statisticsDTO.getId() == null) {
throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull");
}
StatisticsDTO result = statisticsService.save(statisticsDTO);
return ResponseEntity.ok().headers(HeaderUtil.createEntityUpdateAlert(applicationName, true, ENTITY_NAME,
statisticsDTO.getId().toString())).body(result);
}
/**
* {@code GET /statistics} : get all the statistics.
*
* @param pageable the pagination information.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and the list
* of statistics in body.
*/
@GetMapping("/statistics")
@PreAuthorize("hasAnyRole('ADMIN')")
public ResponseEntity<List<StatisticsDTO>> getAllStatistics(Pageable pageable) {
log.debug("REST request to get a page of Statistics");
Page<StatisticsDTO> page = statisticsService.findAll(pageable);
HttpHeaders headers = PaginationUtil
.generatePaginationHttpHeaders(ServletUriComponentsBuilder.fromCurrentRequest(), page);
return ResponseEntity.ok().headers(headers).body(page.getContent());
}
/**
* {@code GET /statistics/:id} : get the "id" statistics.
*
* @param id the id of the statisticsDTO to retrieve.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body
* the statisticsDTO, or with status {@code 404 (Not Found)}.
*/
@GetMapping("/statistics/{id}")
@PreAuthorize("hasAnyRole('ADMIN')")
public ResponseEntity<StatisticsDTO> getStatistics(@PathVariable Long id) {
log.debug("REST request to get Statistics : {}", id);
Optional<StatisticsDTO> statisticsDTO = statisticsService.findOne(id);
return ResponseUtil.wrapOrNotFound(statisticsDTO);
}
@GetMapping("/statistics/exercise/{id}")
public ResponseEntity<StatisticsDTO> getStatisticsByExerciseId(@PathVariable Long id) {
log.debug("REST request to get Statistics for ExerciseID : {}", id);
Optional<StatisticsDTO> statisticsDTO = statisticsService.findOneByExerciseID(id);
Boolean repoExists = gitlabService.repositoryExists(id.toString());
if (repoExists) {
if (statisticsDTO.isPresent()) {
StatisticsDTO newStats = statisticsDTO.get();
newStats.setViews(newStats.getViews() + 1);
statisticsService.save(newStats);
}
if (!statisticsDTO.isPresent()) {
StatisticsDTO newStats = new StatisticsDTO();
newStats.setDownloads(0);
newStats.setViews(1);
newStats.setExerciseID(id);
statisticsService.save(newStats);
log.debug("Created new statistics entry for exerciseID: {}", id);
statisticsDTO = Optional.of(newStats);
}
return ResponseUtil.wrapOrNotFound(statisticsDTO);
}
else{
return null;
}
}
/**
* {@code DELETE /statistics/:id} : delete the "id" statistics.
*
* @param id the id of the statisticsDTO to delete.
* @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)}.
*/
@DeleteMapping("/statistics/{id}")
@PreAuthorize("hasAnyRole('ADMIN')")
public ResponseEntity<Void> deleteStatistics(@PathVariable Long id) {
log.debug("REST request to delete Statistics : {}", id);
statisticsService.delete(id);
return ResponseEntity.noContent()
.headers(HeaderUtil.createEntityDeletionAlert(applicationName, true, ENTITY_NAME, id.toString()))
.build();
}
/**
* {@code SEARCH /_search/statistics?query=:query} : search for the statistics
* corresponding to the query.
*
* @param query the query of the statistics search.
* @param pageable the pagination information.
* @return the result of the search.
*/
@GetMapping("/_search/statistics")
@PreAuthorize("hasAnyRole('ADMIN')")
public ResponseEntity<List<StatisticsDTO>> searchStatistics(@RequestParam String query, Pageable pageable) {
log.debug("REST request to search for a page of Statistics for query {}", query);
Page<StatisticsDTO> page = statisticsService.search(query, pageable);
HttpHeaders headers = PaginationUtil
.generatePaginationHttpHeaders(ServletUriComponentsBuilder.fromCurrentRequest(), page);
return ResponseEntity.ok().headers(headers).body(page.getContent());
}
}
package at.ac.uibk.gitsearch.web.util;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
/**
* Utility class for HTTP headers creation.
*/
public final class HeaderUtil {
private static final Logger log = LoggerFactory.getLogger(HeaderUtil.class);
private HeaderUtil() {
}
public static HttpHeaders createAlert(String applicationName, String message, String param) {
return io.github.jhipster.web.util.HeaderUtil.createAlert(applicationName, message, param);
}
public static HttpHeaders createEntityCreationAlert(String applicationName, boolean enableTranslation, String entityName, String param) {
return io.github.jhipster.web.util.HeaderUtil.createEntityCreationAlert(applicationName, enableTranslation, entityName, param);
}
public static HttpHeaders createEntityUpdateAlert(String applicationName, boolean enableTranslation, String entityName, String param) {
return io.github.jhipster.web.util.HeaderUtil.createEntityUpdateAlert(applicationName, enableTranslation, entityName, param);
}
public static HttpHeaders createEntityDeletionAlert(String applicationName, boolean enableTranslation, String entityName, String param) {
return io.github.jhipster.web.util.HeaderUtil.createEntityDeletionAlert(applicationName, enableTranslation, entityName, param);
}
public static HttpHeaders createFailureAlert(String applicationName, boolean enableTranslation, String entityName, String errorKey, String defaultMessage) {
HttpHeaders headers = io.github.jhipster.web.util.HeaderUtil.createFailureAlert(applicationName, enableTranslation, entityName, errorKey, defaultMessage);
headers.add("X-" + applicationName + "-message", defaultMessage);
return headers;
}
/**
* Creates a authorization headers for a given username and password
* @param username the username
* @param password the password
* @return the acceptHeader
*/
public static HttpHeaders createAuthorization(String username, String password) {
HttpHeaders acceptHeaders = new HttpHeaders() {
{
set(com.google.common.net.HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.toString());
set(com.google.common.net.HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON.toString());
}
};
String authorization = username + ":" + password;
String basic = new String(Base64.getEncoder().encode(authorization.getBytes(StandardCharsets.UTF_8)));
acceptHeaders.set("Authorization", "Basic " + basic);
return acceptHeaders;
}
}
\ No newline at end of file