Skip to content

Commit

Permalink
some fixes, ready to release
Browse files Browse the repository at this point in the history
  • Loading branch information
emiliorighi committed Oct 15, 2024
1 parent 20f69ee commit 8c9feeb
Show file tree
Hide file tree
Showing 17 changed files with 70 additions and 141 deletions.
15 changes: 4 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,13 @@ This project aims to provide a user-friendly interface to show and manage biodiv
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.10363191.svg)](https://doi.org/10.5281/zenodo.10363191)


## Online instances
* [CBP](https://dades.biogenoma.cat)
* [EBP](https://ebp.biogenoma.cat/)
## API specs and Instances

## API specs
[API](https://guigolab.github.io/biogenome-portal/)
See the API specs [here](https://guigolab.github.io/biogenome-portal/)

## Full Documentation
## Docs

Full documentation is now [HERE](https://github.com/guigolab/biogenome-portal/wiki)
Full documentation is now [here](https://github.com/guigolab/biogenome-portal/wiki)

<!-- CONTRIBUTING -->
## Contributing
Expand All @@ -30,14 +27,10 @@ Don't forget to give the project a star! Thanks again!
4. Push to the Branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request

<!-- LICENSE -->
## License

Distributed under the MIT License. See `LICENSE.txt` for more information.

<p align="right">(<a href="#top">back to top</a>)</p>

<!-- CONTACT -->
## Contact

Emilio Righi - emilio.righi@crg.eu
Expand Down
2 changes: 1 addition & 1 deletion biogenome-client/src/components/charts/BarChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ await fetchData()
const chartOptions = computed(() => {
const total = itemStore.stores[model].total || Object.values(data.value).reduce((acc, val) => acc + val, 0)
const total = Object.values(data.value).reduce((acc, val) => acc + val, 0)
return getChartOptions(type, total)
})
const chartData = computed(() => {
Expand Down
2 changes: 1 addition & 1 deletion biogenome-client/src/components/charts/PieChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ await fetchData()
const chartOptions = computed(() => {
const total = itemStore.stores[model].total || Object.values(data.value).reduce((acc, val) => acc + val, 0)
const total = Object.values(data.value).reduce((acc, val) => acc + val, 0)
return getChartOptions(type, total)
})
const chartData = computed(() => {
Expand Down
10 changes: 9 additions & 1 deletion biogenome-client/src/layouts/Layout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,21 @@ import { useBreakpoint } from 'vuestic-ui'
import { useGlobalStore } from "../stores/global-store"
import NavBar from '../components/navbar/Navbar.vue'
import Sidebar from '../components/sidebar/Sidebar.vue'
import { onMounted } from 'vue';
import { onMounted, watch } from 'vue';
import { useItemStore } from '../stores/items-store';
import { useRoute } from 'vue-router';
const itemStore = useItemStore()
const globalStore = useGlobalStore()
const breakpoints = useBreakpoint()
const route = useRoute()
onMounted(async () => {
if (!globalStore.isAuthenticated) await globalStore.checkUserIsLoggedIn()
})
watch(() => route.name, () => {
itemStore.isDashBoard = route.name === 'dashboard'
})
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import { useAnnotationStore } from '../../../../stores/annotation-store'
import AuthService from '../../../../services/clients/AuthService'
import AnnotationService from '../../../../services/clients/AnnotationService'
import { AxiosError } from 'axios'
import { useRouter } from 'vue-router'
const { init } = useToast()
const annotationStore = useAnnotationStore()
Expand All @@ -74,6 +75,7 @@ const props = defineProps<{
name?: string
}>()
const router = useRouter()
const emits = defineEmits(['onLoading'])
watch(() => props.name, (v) => {
Expand Down Expand Up @@ -135,7 +137,8 @@ async function handleSubmit() {
try {
emits('onLoading', true)
const { data } = props.name ? await AuthService.updateAnnotation(props.name, requestData) : await AuthService.createAnnotation(requestData)
init({ message: data, color: 'success' })
init({ message: data + ' saved!', color: 'success' })
router.push({name:'cms-assemblies'})
} catch (error) {
const axiosError = error as AxiosError
if (axiosError.response && axiosError.response.data) {
Expand Down
27 changes: 6 additions & 21 deletions biogenome-client/src/pages/cms/assembly/Assemblies.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,21 @@
<p class="mb-4">Add genome annotations, chromosome aliases or delete assemblies </p>
<va-form @submit.prevent="handleSubmit">
<div class="row align-end">
<va-input v-model="filter" label="search assembly" class="flex lg4 md4 sm12 xs12"></va-input>
<div class="flex">
<va-checkbox indeterminate v-model="hasAliases" label="Has chromosome aliases?"></va-checkbox>
<va-input v-model="filter" label="search assembly"/>
</div>
<div class="flex">
<va-button icon="search" @click="handleSubmit"> </va-button>
<va-button icon="cancel" color="danger" @click="reset"> </va-button>
<va-button icon="search" @click="handleSubmit">Search </va-button>
</div>
<div class="flex">
<va-button style="margin-left: 3px;" icon="cancel" color="danger" @click="reset"> Reset </va-button>
</div>
</div>
</va-form>
<va-data-table :items="assemblies"
:columns="['accession', 'scientific_name', 'assembly_name', 'metadata.assembly_info.assembly_level', 'chromosome_aliases', 'delete']">
<va-data-table :items="assemblies" :columns="['accession', 'scientific_name', 'assembly_name', 'delete']">
<template #cell(delete)="{ rowData }">
<va-icon color="danger" name="delete" @click="deleteConfirmation(rowData)" />
</template>
<template #cell(chromosome_aliases)="{ rowData }">
<div class="row">
<div v-if="rowData.has_chromosomes_aliases" class="flex">
<va-button size="small" :href="`${baseURL}/assemblies/${rowData.accession}/chr_aliases`"
icon="download"></va-button>
</div>
<div v-if="rowData.metadata && rowData.metadata.assembly_info.assembly_level === 'Chromosome'" class="flex">
<va-button :to="{ name: 'chr-aliases', params: { accession: rowData.accession } }" size="small"
icon="add" />
</div>
</div>
</template>
</va-data-table>
<div class="row justify-center">
<div class="flex">
Expand All @@ -56,9 +44,6 @@ import AssemblyService from '../../../services/clients/AssemblyService'
import AuthService from '../../../services/clients/AuthService'
import { useToast } from 'vuestic-ui/web-components'
const baseURL = import.meta.env.VITE_BASE_PATH ? import.meta.env.VITE_BASE_PATH + '/api' : '/api'
const { init } = useToast()
const initPagination = {
offset: 0,
Expand Down
58 changes: 0 additions & 58 deletions biogenome-client/src/pages/cms/uploads/ChrAliasesForm.vue

This file was deleted.

7 changes: 0 additions & 7 deletions biogenome-client/src/router/cms-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,6 @@ export const cmsRoutes = [
beforeEnter: [isAdmin],
component: () => import('../pages/cms/annotation/AnnotationForm.vue'),
},
{
name: 'chr-aliases',
path: 'chr-aliases/:accession',
props: true,
beforeEnter: [isAdmin],
component: () => import('../pages/cms/uploads/ChrAliasesForm.vue')
},
{
name: 'insdc-form',
path: 'insdc-form',
Expand Down
3 changes: 0 additions & 3 deletions biogenome-client/src/services/clients/AuthService.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,6 @@ class AuthService {
importAssembly(accession) {
return auth.post(`/assemblies/${accession}`)
}
uploadRefNameAliases(accession, formData) {
return auth.post(`/assemblies/${accession}/chr_aliases`, formData)
}
deleteAssembly(accession) {
return auth.delete(`/assemblies/${accession}`)
}
Expand Down
16 changes: 11 additions & 5 deletions biogenome-client/src/stores/items-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export const useItemStore = defineStore('item', {
showChartModal: false,
currentModel: "",
isTableLoading: false,
isDashBoard: false,
isTSVLoading: false,
toast: useToast().init
}
Expand Down Expand Up @@ -118,11 +119,16 @@ export const useItemStore = defineStore('item', {
//incoming model may not correspond to currentModel
async getStats(model: string, field: string) {
try {
//filter out filter, and sort fields
const filteredEntries = Object.entries(this.stores[model].searchForm).filter(([k, v]) => !Object.keys(staticFilters).includes(k))
const query = Object.fromEntries(filteredEntries)
if (this.country) query['countries'] = this.country
if (this.parentTaxon) query['taxon_lineage'] = this.parentTaxon
let query = {}
if (!this.isDashBoard) {

const filteredEntries = Object.entries(this.stores[model].searchForm).filter(([k, v]) => !Object.keys(staticFilters).includes(k))
if (this.country) filteredEntries.push(['countries', this.country])
if (this.parentTaxon) filteredEntries.push(['taxon_lineage', this.parentTaxon])

query = Object.fromEntries(filteredEntries)
}


const { data } = await StatisticsService.getModelFieldStats(model, field, query)
return data
Expand Down
1 change: 1 addition & 0 deletions server/db/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class INSDCStatus(Enum):
SAMPLE = 'Biosample Submitted'
READS = 'Reads Submitted'
ASSEMBLIES = 'Assemblies Submitted'
ANNOTATIONS = 'Annotation Completed'

class Roles(Enum):
##CRUD LOCAL_SAMPLES
Expand Down
2 changes: 0 additions & 2 deletions server/helpers/assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ def save_chromosomes(assembly_obj):
new_chromosomes = [chr for chr in chromosomes_to_save if chr.accession_version and chr.accession_version not in existing_chromosomes]
if new_chromosomes:
print(f"Saving a total of {len(new_chromosomes)} chromosomes")

Chromosome.objects.insert(new_chromosomes)
assembly_obj.chromosomes = [chr.accession_version for chr in chromosomes_to_save if chr.accession_version]
else:
print(f"Chromosomes not found for {accession}")
2 changes: 1 addition & 1 deletion server/jobs/assemblies.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def import_assemblies_by_bioproject(project_accession=None):
except Exception as e:
print(e)
print(f"Impossible to save assembly {new_accession}, 'skipping it..")
Chromosome.objects(accession_version__in=parsed_assembly.chromosomes).delete()
Chromosome.objects(metadata__assembly_accession=new_accession).delete()
continue

print(f"Job executed. Saved {saved_assemblies} out of {new_ids_length}")
Expand Down
6 changes: 0 additions & 6 deletions server/rest/assembly/assemblies_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,6 @@ class AssemblyChrAliasesApi(Resource):
def get(self,accession):
return assemblies_service.get_chr_aliases_file(accession)

@data_manager_required()
@jwt_required()
def post(self,accession):
msg = assemblies_service.store_chromosome_aliases(accession, request)
return Response(json.dumps(msg), mimetype="application/json", status=200)

class AssembliesRelatedChromosomesApi(Resource):
def get(self,accession):
chromosomes = assemblies_service.get_related_chromosomes(accession)
Expand Down
48 changes: 29 additions & 19 deletions server/rest/assembly/assemblies_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
import io

def get_related_chromosomes(accession):
assembly = get_assembly(accession)
return Chromosome.objects(accession_version__in=assembly.chromosomes).exclude('id')
ass = get_assembly(accession)
chromosomes = Chromosome.objects(metadata__assembly_accession=accession)
if not chromosomes.count():
chromosomes = Chromosome.objects(accession_version__in=ass.chromosomes)
return chromosomes.exclude('id')

def get_assemblies(args):
return data.get_items('assemblies', args)
Expand Down Expand Up @@ -77,28 +80,35 @@ def delete_assembly(accession):

return accession

def store_chromosome_aliases(accession, request):
assembly = get_assembly(accession)
aliases_file = request.files.get('chr_aliases')
if not aliases_file:
raise BadRequest(description=f"chr_aliases file is required!")

assembly.chromosomes_aliases = aliases_file.read()
assembly.has_chromosomes_aliases = True
assembly.save()
return "Chromosome aliases successfully updated"

def get_related_annotations(accession):
get_assembly(accession)
return GenomeAnnotation.objects(assembly_accession=accession).exclude('id','created').to_json()

def get_chr_aliases_file(accession):
assembly_obj = get_assembly(accession)
if not assembly_obj.has_chromosomes_aliases:
raise BadRequest(description=f"Assembly {accession} lacks of chromosome aliases file")

# Query chromosomes based on accession_version
chromosomes = Chromosome.objects(accession_version__in=assembly_obj.chromosomes).as_pymongo()

if not chromosomes:
raise BadRequest(description=f"Assembly {accession} lacks chromosomes")

# Prepare the TSV data
tsv_data = io.StringIO()

# Assuming chromosomes is a list of dictionaries with fields 'name' and 'accession_version'
for chromosome in chromosomes:
chr_name = chromosome.get('metadata', {}).get('name')
accession_version = chromosome.get('accession_version')
tsv_data.write(f"{chr_name}\t{accession_version}\n")

tsv_data.seek(0) # Go back to the start of the StringIO object

# Send the TSV as a downloadable file
return send_file(
io.BytesIO(assembly_obj.chromosomes_aliases),
mimetype='text/plain',
as_attachment=True,
download_name=f'{assembly_obj.accession}_chr_aliases.txt')

io.BytesIO(tsv_data.getvalue().encode('utf-8')), # Convert StringIO to bytes
mimetype='text/tab-separated-values',
as_attachment=True,
download_name=f'{assembly_obj.accession}_chr_aliases.tsv'
)
4 changes: 2 additions & 2 deletions server/rest/stats/stats_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@

class FieldStatsApi(Resource):
def get(self, model, field):
resp,status = stats_service.get_stats(model, field, request.args)
return Response(json.dumps(resp, default=str),mimetype="application/json", status=status)
json_resp,status = stats_service.get_stats(model, field, request.args)
return Response(json_resp,mimetype="application/json", status=status)

3 changes: 1 addition & 2 deletions server/rest/stats/stats_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ def get_stats(model, field, query):
}
# Sort the response dictionary
sorted_response = {key : response[key] for key in sorted(response)}

return sorted_response, 200
return data_helper.dump_json(sorted_response), 200

except Exception as e:
print(e)
Expand Down

0 comments on commit 8c9feeb

Please sign in to comment.